Werken met de database in Drupal 7 – les 8 – Insertquery’s (INSERT INTO)
Insertquery’s moeten altijd gebruikmaken van de querybuilder. Sommige databases vereisen speciale handlers voor LOB’s (Large Objects, zoals TEXT in MySQL) en BLOB’s (Binary Large Objects). Daarom is een abstractielaag noodzakelijk, zodat de specifieke database-driver deze correct kan afhandelen.
Insertquery’s beginnen met de functie db_insert():
<?php $query = db_insert('node', $options); ?>
Deze query maakt een queryobject aan dat één of meerdere records in de tabel node invoegt. Merk op dat je geen accolades rond de tabelnaam hoeft te plaatsen — de querybuilder zorgt daar automatisch voor.
Een insertquery gebruikt een Fluent API. Dat betekent dat alle methoden (inclusief execute()) het object zelf retourneren, zodat method chaining mogelijk is.
Insertquery’s ondersteunen verschillende patronen, afhankelijk van het doel. Het basisprincipe is dat je de velden opgeeft waarin je gegevens wilt invoegen, en vervolgens de waarden definieert die in die velden moeten worden geplaatst. De meest gebruikte vormen worden hieronder uitgelegd.
Compacte vorm
De voorkeursvorm voor de meeste insertquery’s is de compacte vorm:
<?php $nid = db_insert('node') ->fields(array( 'title' => 'Example', 'uid' => 1, 'created' => REQUEST_TIME, )) ->execute(); ?>
Deze query is equivalent aan de volgende SQL-instructie:
INSERT INTO {node} (title, uid, created) VALUES ('Example', 1, 1221717405);
In dit voorbeeld worden de sleutels (veldnamen) gekoppeld aan de waarden die worden ingevoegd.
<?php db_insert('node') ?>
Deze regel maakt een nieuw queryobject aan voor de tabel node.
<?php ->fields(array( 'title' => 'Example', 'uid' => 1, 'created' => REQUEST_TIME, )) ?>
De methode fields() accepteert meerdere parameters, maar meestal wordt één associatieve array gebruikt. De sleutels van de array zijn de kolomnamen in de database, en de waarden zijn de gegevens die moeten worden ingevoegd. Het resultaat is een invoegquery voor de opgegeven tabel.
<?php ->execute(); ?>
In tegenstelling tot de meeste andere querymethoden retourneert execute() niet het queryobject, maar de waarde van het auto-increment-veld dat is gebruikt bij het invoegen. Voor de tabel node is dit bijvoorbeeld de nid. Als de tabel geen auto-incrementveld bevat, retourneert execute() een ongedefinieerde waarde en moet je die niet gebruiken. In de meeste gevallen is deze compacte vorm de aanbevolen manier om insertquery’s te schrijven.
Eenvoudige vorm
<?php $nid = db_insert('node') ->fields(array('title', 'uid', 'created')) ->values(array( 'title' => 'Example', 'uid' => 1, 'created' => REQUEST_TIME, )) ->execute(); ?>
Deze query is functioneel identiek aan de vorige en levert hetzelfde resultaat op:
<?php ->fields(array('title', 'uid', 'created')) ?>
Wanneer fields() wordt aangeroepen met een genummerde array in plaats van een associatieve, worden alleen de kolomnamen ingesteld, zonder waarden. Dit is handig voor multi-insertquery’s.
<?php ->values(array( 'title' => 'Example', 'uid' => 1, 'created' => REQUEST_TIME, )) ?>
De methode values() beschrijft een associatieve array van veldnamen en de waarden die erin moeten worden ingevoegd. Deze methode kan ook een genummerde array accepteren, maar dan moet de volgorde van de waarden exact overeenkomen met de volgorde van de velden in fields(). Met associatieve arrays maakt de volgorde niet uit — ze zijn beter leesbaar en daarom gebruikelijker. Genummerde arrays komen zelden voor in insertquery’s, omdat de compacte vorm meestal handiger is. De belangrijkste reden om fields() en values() te scheiden, is bij multi-insertquery’s.
Multi-insertquery’s
Een insertquery kan meerdere sets van waarden accepteren. De methode values() kan dus meerdere keren worden aangeroepen, één keer per record dat moet worden ingevoegd. In de meeste databases worden deze invoegingen gecombineerd in één transactie voor betere prestaties. In MySQL resulteert dit in een syntaxis als onderstaande:
<?php $values = array( array( 'title' => 'Example', 'uid' => 1, 'created' => REQUEST_TIME, ), array( 'title' => 'Example 2', 'uid' => 1, 'created' => REQUEST_TIME, ), array( 'title' => 'Example 3', 'uid' => 2, 'created' => REQUEST_TIME, ), ); $query = db_insert('node')->fields(array('title', 'uid', 'created')); foreach ($values as $record) { $query->values($record); } $query->execute(); ?>
De bovenstaande code voert drie invoegingen uit binnen één enkele query, wat efficiënter is dankzij de database-API. Merk op dat we het queryobject in een variabele hebben opgeslagen, zodat we de lus kunnen doorlopen en values() meerdere keren kunnen aanroepen.
In dit geval is het resultaat gelijkwaardig aan drie afzonderlijke queries:
INSERT INTO {node} (title, uid, created) VALUES ('Example', 1, 1221717405); INSERT INTO {node} (title, uid, created) VALUES ('Example2', 1, 1221717405); INSERT INTO {node} (title, uid, created) VALUES ('Example3', 2, 1221717405);
Merk op dat bij multi-inserts de returnwaarde van execute() ongedefinieerd is en afhankelijk van de database-driver. Je moet er dus niet op vertrouwen.
Insert gebaseerd op een SELECT-query (samenvattende tabel)
Als je een tabel wilt vullen met gegevens uit andere tabellen (bijvoorbeeld een samenvattende tabel), kun je dit doen door eerst met PHP gegevens te verzamelen en vervolgens in te voegen, of door een query in de vorm van INSERT INTO ... SELECT FROM te gebruiken.
In dit voorbeeld willen we een tabel mytable maken met alle nid en username van nodes in het systeem.
Drupal 6
<?php db_query('INSERT INTO {mytable} (nid, name) SELECT n.nid, u.name FROM {node} n LEFT JOIN {users} u on n.uid = u.uid WHERE n.type = "%s"', array ('page')); ?>
Drupal 7
<?php // Bouw de SELECT-query. $query = db_select('node', 'n'); // Voeg een join toe met de users-tabel. $query->join('users', 'u', 'n.uid = u.uid'); // Voeg de gewenste velden toe. $query->addField('n', 'nid'); $query->addField('u', 'name'); // Voeg een conditie toe voor alleen 'page'-nodes. $query->condition('type', 'page'); // Voer de insert uit. db_insert('mytable') ->from($query) ->execute(); ?>
Standaardwaarden gebruiken (Default values)
Normaal gesproken, als je voor een veld geen waarde opgeeft en de database een standaardwaarde definieert, wordt die standaardwaarde automatisch ingevoegd. In sommige gevallen wil je echter expliciet aangeven dat de database de standaardwaarden moet gebruiken — bijvoorbeeld als je alle velden met hun standaardwaarden wilt vullen. Hiervoor gebruik je de methode useDefaults().
<?php $query->useDefaults(array('field1', 'field2')); ?>
Deze code dwingt de query om voor de velden field1 en field2 de standaardwaarden te gebruiken. Let op: het is een fout om dezelfde velden zowel in useDefaults() als in fields() of values() op te nemen — dit zal een foutmelding veroorzaken.