web-dev-qa-db-ja.com

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

条件ステートメントを使用して「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)');
26
JurgenR

特定の例では、条件を次のように記述するだけです。

_$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_の値として受け入れます。 db_select()による問題は、_$operator_の値が_"IN"_と等しい場合に実際に使用できることです。 INの値として使用される場合を除いて、DBTNG条件では副選択は機能しません を参照してください。

conditionのサブクエリで「NOT IN」演算子を使用する唯一の方法は、次のとおりです。

  • サブクエリを実行して配列を取得する
  • 次のスニペットのように、条件を設定してメインクエリを実行します。

    _$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();
_
38
kiamlaluno

複雑なクエリを作成するときは、必ず db_query() の代わりに db_select() を使用してください。

  1. 現在のDrupalデータベースAPIでサブクエリを使用してNOT IN句を書き込むことはできません(これは 既知の問題 の問題です)。
  2. クエリを dynamic にする必要がない場合(したがって、他のモジュールによって書き換えられます)、 気にしないでください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は不要です。

3
tostinni

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

例:

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

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

2
Berdir

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);
1
David Thomas

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

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

それは正常に動作します。

0
Riccardo Ravaro