クエリで「NOT IN」を使用するにはどうすればよいですか?


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'ですか?
ЕлинЙ.

回答:


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);
    }
  • 条件節(「副選択」)で報告されているように、によって返されるSelectQuery::condition()オブジェクトなど、のSelectQueryInterface値として実装するオブジェクトも受け入れます。問題は、の値がに等しいときに実際に使用できることです。INの値として使用する場合を除き、DBTNG条件では副選択が機能しないを参照してください。$valuedb_select()$operator"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();

ここに、私が書いたビューのカスタムフィルターのサブクエリの例を示します。リンク
ロジャー

1
「サブセレクトは、INの値として使用される場合を除き、DBTNG条件では機能しません」はDrupal 8.3-
ジョナサン

3

複雑なクエリを作成するときは、のdb_query()代わりに必ず使用する必要がありdb_select()ます。

  1. NOT IN現在のDrupalデータベースAPIでサブクエリを使用して句を作成することはできません(これは解決されている既知の問題です)。
  2. クエリを動的にする必要がない場合(他のモジュールによって書き換えられるため)、を使用してこのような複雑なクエリを記述しようとしないくださいdb_select()
  3. サブクエリはまだ十分にサポートされていません(私の以前の回答を参照してください)。SQLの記述に慣れている場合は、使用する方が簡単db_query()です。

あなたのクエリに関して、あなたがサブクエリを使用したい理由がわかりません(あなたのexempleを単純化していない限り)?次のように簡単に記述できます。

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

DISTINCTnid主キーのように必要ないため、複製されません。


2
#2に関して、OPはノードを選択しています。AFAIK db_select()は、必要な 'node_access'タグを提供する唯一の方法です。この場合、db_select()が唯一の選択肢になります。
キース

2

クエリに任意のwhere条件を追加できるwhere()あります。

例:

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

keithmが述べたように、ユーザーに表示されるノードを選択するときは、db_select()およびaddTag( 'node_access')を使用する必要があります。


1

NOT IN副選択でdb_selectを使用する簡単な方法は、あまり知られていないものを使用することです

$ query-> where

任意の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);

0

$ subquery_valuesは、サブクエリの結果としての$ key => $ nid形式の配列です

$query->condition('node.nid', array_values($subquery_values), "NOT IN");

正常に動作します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.