当前位置: 首页>>建站开发>>正文


如何在查询中使用“NOT IN”?

webfans 建站开发 , , 去评论

问题描述

使用条件语句编写包含’NOT IN’的查询的正确方法是什么?

我的查询如下:

SELECT DISTINCT nid FROM node WHERE language NOT IN 
  (SELECT language 
    FROM languages WHERE language = 'ab');

我尝试过以下内容:

$query->condition('n.' . $key, $value, 'not in (select language from 
  languages where language = $value)');

最佳解决方法

在具体示例中,您应该简单地将条件写为:

$query->condition('n.language', 'ab', '<>');

在通用情况下,您需要根据从sub-query返回的值选择数据库中的行,您应该考虑以下内容:

  • “NOT IN”被接受为SelectQuery::condition()的操作符。实际上,将执行以下查询:

    $query = db_select('node', 'n')->fields('n');
    $query->condition('n.nid', array(1, 2, 3), 'NOT IN');
    $nodes = $query->execute();
    
    foreach ($nodes as $node) {
      dsm($node->nid);
    }
    
  • Conditional clauses(“Subselects”)中所报道的,SelectQuery::condition()还接受实施SelectQueryInterface作为$value的值的对象,例如由db_select()返回的物质;问题是,当$operator的值等于"IN"时,实际上你可以使用它。请参阅Subselects don’t work in DBTNG conditions, except when used as value for IN

我可以看到在condition中使用”NOT IN”运算符和sub-query的唯一方法是:

  • 执行子查询以获取数组

  • 执行主查询设置条件,如下面的代码片段所示

    $query->condition($key, $subquery_result, 'NOT IN');
    

    $subquery_result是包含sub-query结果的数组。

否则,您可以像其他人所说的那样使用where(),它接受您需要添加的查询部分的字符串。

请记住,db_select()db_query()慢;当你知道查询可以被其他模块改变时,你应该使用第一个。否则,如果其他模块不应使用hook_query_alter()来更改查询,则应使用db_query()。在访问节点的情况下,如果只需要获取用户有权访问的节点,则需要使用db_select()并使用SelectQuery::addTag()添加'node_access'作为查询的标记。例如,blog_page_last()使用以下代码。

  $query = db_select('node', 'n')->extend('PagerDefault');
  $nids = $query
  ->fields('n', array('nid', 'sticky', 'created'))
    ->condition('type', 'blog')
    ->condition('status', 1)
    ->orderBy('sticky', 'DESC')
    ->orderBy('created', 'DESC')
    ->limit(variable_get('default_nodes_main', 10))
    ->addTag('node_access')
    ->execute()
    ->fetchCol();

book_block_view()使用类似的代码。

$select = db_select('node', 'n')
  ->fields('n', array('title'))
  ->condition('n.nid', $node->book['bid'])
  ->addTag('node_access');
$title = $select->execute()->fetchField();

次佳解决方法

编写复杂查询时,绝对应该使用db_query()而不是db_select()

  1. 您不能使用当前Drupal数据库API的子查询编写NOT IN子句(它正在编写know issue)。

  2. 如果您不需要查询为dynamic(因此由其他模块重写),don’t bother尝试使用db_select()编写这样一个复杂的查询。

  3. 子查询尚未得到很好的支持(参见我的previous answer),如果您习惯于编写SQL,那么使用db_query()会更容易。

关于你的查询,我不确定你为什么要使用子查询(除非你简化了你的例子)?你可以像这样轻松地写它:

SELECT nid 
FROM node n INNER JOIN languages l ON n.language = l.language
WHERE language NOT IN ('ab')

DISTINCT不是必需的,因为nid是主键,因此不会重复。

第三种解决方法

还有where(),它允许在查询中添加任意where条件。

例:

$query->where('n.language NOT IN (SELECT language FROMlanguages WHERE language = :lang)', array(':lang' => $value));

正如keithm所提到的,在选择随后向用户显示的节点时,必须使用 db_select()和addTag(‘node_access’)。

参考资料

本文由朵颐IT整理自网络, 文章地址: https://duoyit.com/article/2640.html,转载请务必附带本地址声明。