Arbeiten mit der Datenbank in Drupal 7 – Lektion 8 – Einfüge-Abfragen (INSERT INTO)
Einfüge-Abfragen sollten immer den Query-Builder verwenden. Manche Datenbanken benötigen spezielle Handler für LOBs (Large OBjects, wie TEXT in MySQL) und BLOB-Felder (Binary Large OBjects), daher ist eine Abstraktionsschicht notwendig, damit individuelle DB-Treiber diese behandeln können.
Einfüge-Abfragen beginnen mit der Funktion db_insert()
:
<?php $query = db_insert('node', $options); ?>
Dieser Insert-Query erzeugt ein Objekt, das eine oder mehrere Datensätze in die Tabelle node
einfügt. Tabellennamen müssen nicht in geschweifte Klammern gesetzt werden, der Query-Builder erledigt das automatisch.
Insert-Abfragen verwenden eine Fluent API. Das bedeutet, alle Methoden (einschließlich execute()
) geben das Query-Objekt zurück, um Methodenverketten zu ermöglichen.
Es gibt verschiedene Muster für Insert-Abfragen. Das gebräuchlichste beschreibt die Felder, in die Werte eingefügt werden, und die Werte selbst. Die wichtigsten Formen werden im Folgenden erklärt.
Kompakte Form (Compact form)
Die bevorzugte Form für die meisten Inserts ist die kompakte Form:
<?php $nid = db_insert('node') ->fields(array( 'title' => 'Example', 'uid' => 1, 'created' => REQUEST_TIME, )) ->execute(); ?>
Dies entspricht der SQL-Abfrage:
INSERT INTO {node} (title, uid, created) VALUES ('Example', 1, 1221717405);
Der Code verbindet Spaltennamen mit den einzufügenden Daten.
<?php db_insert('node') ?>
Erzeugt ein neues Insert-Query-Objekt für die Tabelle node
.
<?php ->fields(array( 'title' => 'Example', 'uid' => 1, 'created' => REQUEST_TIME, )) ?>
Die Methode fields()
akzeptiert mehrere Parameter, meist jedoch ein assoziatives Array. Die Schlüssel sind die Spaltennamen, die Werte die einzufügenden Daten. Dies definiert die Einfüge-Abfrage.
<?php ->execute(); ?>
Im Gegensatz zu anderen Methoden gibt execute()
den Wert der Auto-Increment-Spalte zurück, die für die Einfügung verwendet wurde (z. B. nid
in der Tabelle node
). Wenn kein Auto-Increment-Feld vorhanden ist, ist der Rückgabewert undefiniert und nicht verlässlich. In den meisten Fällen ist dies die bevorzugte Insert-Form.
Vereinfachte Form (Degenerate form)
<?php $nid = db_insert('node') ->fields(array('title', 'uid', 'created')) ->values(array( 'title' => 'Example', 'uid' => 1, 'created' => REQUEST_TIME, )) ->execute(); ?>
Diese Abfrage ist äquivalent zu der vorherigen und hat denselben Effekt.
<?php ->fields(array('title', 'uid', 'created')) ?>
Wenn fields()
mit einem indizierten Array (statt assoziativem) aufgerufen wird, definiert es nur die Spaltennamen, ohne Werte. Dies ist nützlich für Multi-Insert-Abfragen.
<?php ->values(array( 'title' => 'Example', 'uid' => 1, 'created' => REQUEST_TIME, )) ?>
Die Methode values()
nimmt ein assoziatives Array mit Feldnamen und Werten an oder ein indiziertes Array. Beim indizierten Array muss die Reihenfolge der Werte der Reihenfolge der Felder in fields()
entsprechen. Bei assoziativen Arrays ist die Reihenfolge irrelevant. Indizierte Arrays sind seltener, die kompakte Form ist meist vorzuziehen. Der Grund für die Trennung von fields()
und values()
liegt vor allem in Multi-Insert-Queries.
Multi-Insert
Insert-Query-Objekte können mehrere Werte aufnehmen, indem values()
mehrfach aufgerufen wird. Viele DB-Treiber führen diese Multi-Insert-Queries in einer Transaktion aus, was die Performance verbessert. MySQL verwendet dafür den Syntax mit mehreren Wertpaaren.
<?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(); ?>
Das Beispiel zeigt drei Inserts als Batch, welche effizient vom DB-Treiber umgesetzt werden. Das Query-Objekt wird in einer Variablen gehalten, um die Schleife für values()
-Aufrufe zu ermöglichen.
Getrennte fields()
und values()
Aufrufe sind äquivalent zu drei einzelnen Insert-Anweisungen:
INSERT INTO {node} (title, uid, created) VALUES ('Example', 1, 1221717405); INSERT INTO {node} (title, uid, created) VALUES ('Example 2', 1, 1221717405); INSERT INTO {node} (title, uid, created) VALUES ('Example 3', 2, 1221717405);
Beachten Sie, dass bei Multi-Insert-Queries der Rückgabewert von execute()
undefiniert ist und nicht vertrauenswürdig sein sollte, da er je nach DB-Treiber variiert.
Einfügen basierend auf SELECT-Abfragen (Aggregat-Tabellen)
Wenn Sie eine Tabelle mit Ergebnissen aus anderen Tabellen füllen wollen (Aggregat-Tabellen), können Sie die Daten per PHP auslesen und dann einfügen oder eine Insert-Select-Abfrage nutzen, die für jede Zeile einen Insert durchführt.
Beispiel: Tabelle "mytable" mit allen nid
und username
aller Knoten:
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 // SELECT-Abfrage bauen. $query = db_select('node', 'n'); // Join mit users-Tabelle. $query->join('users', 'u', 'n.uid = u.uid'); // Gewünschte Felder hinzufügen. $query->addField('n','nid'); $query->addField('u','name'); // Bedingung nur page-Typen. $query->condition('type', 'page'); // Insert ausführen. db_insert('mytable') ->from($query) ->execute(); ?>
Standardwerte
Wenn für ein Feld kein Wert angegeben wird und es in der Tabellendefinition einen Default-Wert gibt, setzt die Datenbank diesen automatisch. In manchen Fällen muss man jedoch explizit angeben, dass die DB Standardwerte nutzen soll. Dies erfolgt mit der Methode useDefaults()
.
<?php $query->useDefaults(array('field1', 'field2')); ?>
Dieser Code weist den Query an, für die Felder field1
und field2
die Standardwerte zu verwenden. Beachten Sie, dass es zu Fehlern kommt, wenn dieselben Felder in useDefaults()
und in fields()
oder values()
definiert werden.