Last updated February 1, 2013. Created by Crell on September 18, 2008.
Edited by peterx, Ralt, kalman.hosszu, Jaypan. Log in to edit this page.
Insert queries must always use a query builder object. Certain databases require special handling for LOB (Large OBject, such as TEXT on MySQL) and BLOB (Binary Large OBject) fields, so a layer of abstraction is required to allow individual database drivers to implement whatever special handling they require.
Insert queries are started using the db_insert() function as follows:
<?php
$query = db_insert('node', $options);
?>That creates an insert query object that will insert one or more records to the node table. Note that braces are not required around the table name as the query builder will handle that automatically.
The insert query object uses a fluent API. That is, all methods (except execute()) return the query object itself allowing method calls to be chained. In many cases, that means the query object will not need to be saved to a variable at all.
The insert query object supports a number of different usage patterns to support different needs. In general, the workflow consists of specifying the fields that the query will insert into, specifying the values the query will insert for those fields, and executing the query. The most common recommended usage patterns are listed below.
Compact form
The preferred form for most Insert queries is the compact form:
<?php
$nid = db_insert('node')
->fields(array(
'title' => 'Example',
'uid' => 1,
'created' => REQUEST_TIME,
))
->execute();
?>This will result in the equivalent of the following query:
INSERT INTO {node} (title, uid, created) VALUES ('Example', 1, 1221717405);
The above snippet chains together the key parts of the insert process.
<?php
db_insert('node')
?>This line creates a new insert query object for the node table.
<?php
->fields(array(
'title' => 'Example',
'uid' => 1,
'created' => REQUEST_TIME,
))
?>The fields() method takes several forms of parameters, but a single associative array is the most common. The keys of the array are the table columns into which to insert and the values are the corresponding values to insert. That will result in a single insert query against the specified table.
<?php
->execute();
?>The execute() method tells the query to run. Unless this method is called, the query does not execute.
Unlike other methods on the Insert query object, which return the query object itself, execute() returns the value of an auto-increment (serial type in hook_schema()) field that was populated by the Insert query, if any. That's why the return value from it is assigned to $nid in the example above. If there is no auto-increment field, the return value from execute() is undefined and should not be trusted.
In the typical case, this is the preferred format for Insert queries.
Degenerate form
<?php
$nid = db_insert('node')
->fields(array('title', 'uid', 'created'))
->values(array(
'title' => 'Example',
'uid' => 1,
'created' => REQUEST_TIME,
))
->execute();
?>This is the somewhat more verbose equivalent of the previous query, and will have the exact same result.
<?php
->fields(array('title', 'uid', 'created'))
?>When fields() is called with an indexed array instead of an associative array, it sets only the fields (database columns) that will be used in the query without setting any values for them. That is useful for running a multi-insert query later.
<?php
->values(array(
'title' => 'Example',
'uid' => 1,
'created' => REQUEST_TIME,
))
?>This method call specifies an associative array of field names to values to insert into those fields. The values() method may also take an indexed array instead. If an indexed array is used, the order of values must match the order of fields in the fields() method. If an associative array is used, it may be in any order. Generally the associative array is preferred for readability.
This query form is rarely used, as the compact form is preferred. In most cases the only reason to separate fields() and values() is when running a multi-insert query.
Multi-insert form
The Insert query object may also take multiple value sets. That is, values() may be called multiple times to enqueue several insert statements together. Exactly how that happens will depend on the capabilities of the database in question. On most databases, multiple insert statements will be executed together inside a transaction for greater data integrity and speed. On MySQL, it will use MySQL's multi-value insert syntax.
<?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();
?>The above example will execute three insert statements together as a single unit, using the most efficient method for the particular database driver in use. Note that here we have saved the query object to a variable so that we can loop on $values and call the values() method repeatedly.
In the degenerate case, the above example is equivalent to the following three 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);
Note that on a multi-insert query the return value from execute() is undefined and should not be trusted, as it may vary depending on the database driver.
Inserting based on the results of a select query
If you want to populate a table with results from other tables, you either need to SELECT from the source tables, interate over the data in PHP and insert it into the new table, or you can do a INSERT INTO...SELECT FROM query in which every record which is returned from the SELECT query gets fed into the INSERT query.
In this example, we want to build a table "mytable" which has a node id and a user name for all nodes on the system which are of the page type.
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
// Build the SELECT query.
$query = db_select('node', 'n');
// Join to the users table.
$query->join('users', 'u', 'n.uid = u.uid');
// Add the fields we want.
$query->addField('n','nid');
$query->addField('u','name');
// Add a condition to only get page nodes.
$query->condition('type', 'page');
// Perform the insert.
db_insert('mytable')
->from($query)
->execute();
?>Default values
In normal circumstances, if you do not specify a value for a given field and a default value is defined by the table's schema then the database will silently insert that default value for you. In some cases, however, you need to explicitly instruct the database to use a default value. That includes if you want to use all default values for the entire record. To explicitly tell the database to use the default value for a given field, there is a useDefaults() method.
<?php
$query->useDefaults(array('field1', 'field2'));
?>This line instructs the the query to use the database-defined defaults for fields field1 and field2. Note that it is an error to specify the same field in both useDefaults() and fields() or values(), and an exception will be thrown.
db_insert or db_query
This is a commonly asked question. (See the comments on this page.) What are the difference between db_insert and db_query?
db_insert has each column specified as a separate entry in the fields array and the code can clean each column value. db_query has an SQL string with no way of checking individual columns. If you use db_query with placeholders, the code can check the column values but placeholders are just an option, there is no way to ensure your SQL does not contain values not passed through placeholders.
db_insert passes the request through a set of hooks to let other modules check and modify your requests. this is the right way to work with other modules. db_query is slightly faster because db_query does not pass the request through the hooks. You might save processing time but your code will not let other modules help your code.
db_insert is more likely to work with other databases and future versions of Drupal.
Comments
FYI
It would appear that the following exceptions are ones being referred to in the last sentence above (this is from database.inc):
/**
* Exception thrown if an insert query specifies a field twice.
*
* It is not allowed to specify a field as default and insert field, this
* exception is thrown if that is the case.
*/
class FieldsOverlapException extends Exception {}
/**
* Exception thrown if an insert query doesn't specify insert or default fields.
*/
class NoFieldsException extends Exception {}
This is not currently documented in the db_insert documentation either.
------------
We are born naked, wet, and hungry. Then things get worse.
Is there any way to do an
Is there any way to do an INSERT ... ON DUPLICATE KEY UPDATE in D7 then (for MySQL)?
Edit: Should have kept on reading: http://drupal.org/node/310085
Jordan
did u find a soln for it, if
did u find a soln for it, if yes please tell me
In case anyone googles this
In case anyone googles this like I did; db_merge() does this, though I think the resulting query differs a bit. I only used it in its' simplest form.
how to insert data from a form field?
Hi, maybe you can help me with a basic syntax problem. If what i want is to insert in a table the input the user writes in a custom form field... how should i write it? Could any give me an example or tell me where to read from?
thanks a lot
PIÑA&POLLO
You basically make a
You basically make a hook_myform_submit. This page has more details here http://drupal.org/node/751826 scroll down to submitting forms. I had the same problem recently not intuitive at first but once you figure it out it makes sense. This should help explain getting the information from the form. Hope that helped.
thanks a lot
I'll try as soon as i clear my problems with the .install file (doesn't create my table) :P
Thanks again
PIÑA&POLLO
Using sql functions in insert queries
Is it possible to use any (My)SQL functions with db_insert?
The db_update query allows to use expression(), but I can't find anything similar for inserts.
The most simple example is to use the database NOW() function, if there is no default value of current_timestamp on the table's column. A possible way is to use db_insert()->from($query) and build the function to the query, but it's just too complicated.
Any suggestions, please?
Reusing the query
The only example of reusing the query is with a new values list, a non semantic approach that does not work when you have a variable list of values for each insert. What would be nice is to keep the query object and change the value of fields by name (the fields compact form) then execute the query. You can use the following form.
<?php$insert = db_insert('node')->fields(array('title', 'uid', 'created'));
$nid = $insert->values(array('title' => 'a', 'uid' => 1, 'created' => 5))->execute();
// Use nid.
$nid = $insert->values(array('title' => 'b', 'uid' => 2, 'created' => 6))->execute();
// Use nid.
$nid = $insert->values(array('title' => 'c', 'uid' => 3, 'created' => 7))->execute();
// Use nid.
?>
petermoulding.com/web_architect
How would you handle
How would you handle something like this as a dynamic query?
db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, custom, visibility, pages, title, cache)
SELECT module, delta, :sub_theme as theme, status, weight, region, custom, visibility, pages, title, cache FROM {block} as WHERE b.theme = :base_theme", array(
':sub_theme' => $sub_theme,
':base_theme' => $base_theme
);
Using db_query obviously works, what I'm struggling with is how to get the ":sub_theme as theme" piece of the SELECT into a db_select fields() or addField() method.
Use
Use
$selectQuery->addExpression(':sub_theme', 'theme', $sub_theme)and be careful that addExpression returns the alias, not the$selectQueryobject. To complete your query (untested):<?php
$selectQuery = db_select('block', 'b')
->fields('b', array('module', 'delta', 'status', 'weight', 'region', 'custom', 'visibility', 'title', 'cache')
->condition('theme', $base_theme);
$selectQuery->addExpression('?', 'theme', $sub_theme);
db_insert('block')->from($selectQuery)->execute();
?>
Simple INSERT query example Drupal 6 vs. Drupal 7
The following is an example of a query I converted from D6 into D7 format:
<?php
// Drupal 6 version
db_query('INSERT INTO {vchess_games}
(gid, timestamps, white, black, state, board_white, board_black) ' . "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s')",
$gid, $timestamps, $game['white'], $game['black'], $state, $board_white, $board_black);
// Drupal 7 version
db_insert('vchess_games')
->fields(array(
'gid' => $gid,
'timestamps' => $timestamps,
'white' => $game['white'],
'black' => $game['black'],
'state' => $state,
'board_white' => $board_white,
'board_black' => $board_black
))
->execute();
?>
Pretty easy actually when you follow the example!
drupalshrek
Maintainer of the VChess module visible in use at chess website Chesspos.com
So we don't need to worry
So we don't need to worry about security and bind parameters? I feel uneasy just putting in the value directly. Can anyone confirm???
I was wondering the exact
I was wondering the exact same thing too. Looking over the documentation for converting your code from drupal 6.x to 7.x, it looks like they aren't required, provided you use the dynamic queries (db_insert, db_select). See the Insert example http://drupal.org/node/224333#dbtng.
Additionally if you look at the Database API documentation it also states "to enforce security checks and other good practices" as one of the reasons for the new Drupal 7 database api.
This is also answered over on stackexchange too: http://drupal.stackexchange.com/a/26817/13256
If you are still using db_query though, it's probably a good idea, to continue to using placeholders.
Blog: akb.id.au | Twitter: @alexbergin
Placeholders required for db_query
Placeholders are required for db_query because you supply an SQL statement with no way to clean the input outside of placeholders. db_insert and db_update have columns specified as separate entries in the fields array which lets the code clean the fields. db_insert and db_update also run the request through a bunch of hooks so other modules can modify or stop your request.
petermoulding.com/web_architect
Debugging InsertQuery->from(SelectQuery)
For those of you debugging your complicated queries, note that in insert query coming from a select query, the fields are not added until $insertQuery->preExecute(). This isn't a problem if you're executing it, but it is if you're taking the __toString() of your query to make sure the generated query works right.
Much appreciated
Thank you for pointing this out.
this simple syntax does not work out of the box.
using the basic insert syntax from above. I getnothing enterred to the database and this error shows up in the log:
PDOException: SQLSTATE[HY000]: General error: 1364 Field 'delta' doesn't have a default value: INSERT INTO {field_data_body}
I am trying to save bidy text to a node.
field_
@veeray, anything created as a field has a language and a delta as part of the index. Set delta to zero if you do not need anything else. Each module has a different use for delta column.
Language defaults to an empty string and should be set to 'und', which is defined in a constant, or the site language, or the entity language, depending on the entity. Language can be really complicated. Look in your database to see what is used.
petermoulding.com/web_architect
Example code
<?phpdb_insert('users_roles')
->fields(array('uid'=>1,'rid'=>11))
->execute();
?>