如何在查询中使用“不输入”?


26

使用条件语句编写包含“ 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)');

也许我错过了显而易见的内容,但是您的查询和有SELECT nid FROM node WHERE language != 'ab'什么区别?
ЕлинЙ.

Answers:


38

在特定示例中,您只需将条件写为:

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

在一般情况下,需要根据子查询返回的值选择数据库中的行,则应考虑以下内容:

  • 接受“ 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);
    }
    
  • 条件条款(“ Subselects”)中所述,SelectQuery::condition()还接受实现SelectQueryInterface为value 的对象$value,例如db_select(); 返回的对象。问题是实际上您只能在的值$operator等于时使用它"IN"。请参阅子选择在DBTNG条件下不起作用,除非用作IN的值

我可以看到对子查询使用“ NOT IN”运算符的唯一方法condition是:

  • 执行子查询以获取数组
  • 执行主查询以设置条件,如以下代码片段所示

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

    $subquery_result 是包含子查询结果的数组。

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

记住那db_select()较慢db_query(); 如果您知道查询可能会被其他模块更改,则应使用第一个。否则,如果hook_query_alter()不应使用其他模块来更改查询,则应使用db_query()
对于访问节点,如果仅需要获取用户有权访问的节点,则需要使用db_select()并将其添加'node_access'为查询的标记SelectQuery::addTag()。例如,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();

这是我编写的视图自定义过滤器的子查询示例:链接
Roger

1
“子选择不工作在DBTNG的条件下,作为在值中使用时除”被固定在Drupal 8.3
乔纳森

3

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

  1. 您不能NOT IN使用当前的Drupal数据库API 编写带有子查询的子句(正在解决已知问题)。
  2. 如果您不需要动态查询(因此可以由其他模块重写),请不要尝试使用编写如此复杂的查询db_select()
  3. 子查询还没有得到很好的支持(请参阅我的先前的答案),如果您习惯于编写SQL,则使用起来会更容易db_query()

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

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

DISTINCT不需要,因为nid它是主键,因此不会重复。


2
关于#2,OP正在选择节点。AFAIK db_select()是提供任何必需的“ node_access”标签的唯一方法,在这种情况下,db_select()将是唯一的选择。
keithm

2

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

例:

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

正如keithm所述,在选择随后显示给用户的节点时,必须使用db_select()和addTag('node_access')。


1

将db_select与NOT IN子选择一起使用的更简单方法是使用鲜为人知的

$ query->哪里

添加任意where条件。

例如:

  // Count query for users without rid 3
  $query = db_select('users', 'u');
  $query->fields('u', array('uid'));
  $query->where('u.uid NOT IN(select uid from {users_roles} where rid = :rid)', array(':rid' => 3));  
  $count = $query->countQuery()->execute()->fetchField();
  drupal_set_message($count);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.