条件ステートメントを使用して「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', '<>');
_
一般的なケースでは、サブクエリから返された値に基づいてデータベースの行を選択する必要がある場合、次のことを考慮する必要があります。
「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();
_
複雑なクエリを作成するときは、必ず db_query()
の代わりに db_select()
を使用してください。
NOT IN
句を書き込むことはできません(これは 既知の問題 の問題です)。db_select()
。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')を使用する必要があります。
NOT INサブセレクトでdb_selectを使用する簡単な方法は、ほとんど知られていないものを使用することです
任意の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);
$ subquery_valuesは、サブクエリの結果として$ key => $ nid形式の配列です。
$query->condition('node.nid', array_values($subquery_values), "NOT IN");
それは正常に動作します。