For the background on this, please see http://drupal.org/node/1067802.

Given all that, what situations exists where I might want to use db_select(), or should I be relying solely on db_query?

link|improve this question

feedback

3 Answers

up vote 17 down vote accepted

There are 5 reasons to use SelectQuery

  • You are building dynamic queries with a varying number of conditions, joins, fields and so on. See field_read_fields() for an example.

  • You want to use so called Extenders. Example extenders are PagerDefault (replaces pager_query()) and TableSort (replaces tablesort_sql()). These allow to add additionally functionality to SelectQuery. See also How do you make sortable tables with a pager with data from a custom table?. An example: node_page_default().

  • You want to allow other modules to alter your queries. Then you can add so called tags and SelectQuery will automatically call a corresponding alter hook for that tag. I'm am heavily relying on this with my Privatemsg module (We already did that in D6 with a custom query builder).

  • If you want/need to use the node_access system to only show nodes the user is allowed to see. Just add the 'node_access' tag to your $query. This replaces db_rewrite_sql().

  • SelectQuery has a few features that help to make your code work the same across all supported databases. For example there is SelectQuery::orderRandom(). And if you have a LIKE condition, ->condition('field', $value, 'LIKE') will make sure that it is always a case insensitive comparison. In D6, you had to use LOWER() for that which was much slower. But AFAIK, there aren't more than this two right now.

If none of these reasons apply for a specific case, use db_query().

link|improve this answer
Great answer. Thanks. – Chris Cohen Mar 23 '11 at 12:44
Added a fifth point, database portability features like orderRandom() and case insensitive LIKE. – Berdir Mar 23 '11 at 23:33
Do Extenders come along with db_query() ? I have a complex query with sub-queries using db_query(). How can do pager with db_query() or can I create sub-queries with db_select(). – Sithu Kyaw Jan 30 at 6:10
@Berdir Please see my question drupal.stackexchange.com/questions/21051/… – Sithu Kyaw Jan 30 at 10:47
feedback

The documentation about db_query() says:

Use this function for SELECT queries if it is just a simple query string. If the caller or other modules need to change the query, use db_select() instead.

link|improve this answer
Thanks, but that's quite unspecific. It leaves the definition of 'simple query string' quite open to interpretation. If I'm selecting across 4 tables with 6 joins, is that still a simple query, or should it be done with db_select() instead? – Chris Cohen Mar 23 '11 at 10:29
1  
It's not about "simple query" but, about a "simple query string" and simple actually means hardcoded and not dynamic. See my answer for more details :) – Berdir Mar 23 '11 at 10:39
feedback

In addition to what said from Berdir, I would say that in the case the query is altered from a function (even another function from the same module that is executing the query), then altering the object returned by db_select() is easier than altering the string containing the query.
Another example of when I would use db_select() instead of db_query() is when the query is dynamically built basing on some parameters, or conditions. The following code is the code executed when calling comment_get_display_ordinal():

function comment_get_display_ordinal($cid, $node_type) {
  // Count how many comments (c1) are before $cid (c2) in display order. This is
  // the 0-based display ordinal.
  $query = db_select('comment', 'c1');
  $query->innerJoin('comment', 'c2', 'c2.nid = c1.nid');
  $query->addExpression('COUNT(*)', 'count');
  $query->condition('c2.cid', $cid);
  if (!user_access('administer comments')) {
    $query->condition('c1.status', COMMENT_PUBLISHED);
  }
  $mode = variable_get('comment_default_mode_' . $node_type, COMMENT_MODE_THREADED);

  if ($mode == COMMENT_MODE_FLAT) {
    // For flat comments, cid is used for ordering comments due to
    // unpredicatable behavior with timestamp, so we make the same assumption
    // here.
    $query->condition('c1.cid', $cid, '<');
  }
  else {
    // For threaded comments, the c.thread column is used for ordering. We can
    // use the vancode for comparison, but must remove the trailing slash.
    // See comment_view_multiple().
    $query->where('SUBSTRING(c1.thread, 1, (LENGTH(c1.thread) -1)) < SUBSTRING(c2.thread, 1, (LENGTH(c2.thread) -1))');
  }

  return $query->execute()->fetchField();
}
link|improve this answer
That is exactly what I meant with my first point, doesn't matter if it is the same function or if multiple functions are used. Agreed that it is not very clearly stated :) – Berdir Mar 23 '11 at 19:47
feedback

Your Answer

 
or
required, but never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.