web-dev-qa-db-fra.com

"OERE N'EST PAS DANS (SELECT ...)" avec SelectQuery?

Est-il possible d'ajouter une clause WHERE NOT IN (SELECT...) à un objet SelectQuery? Je regardais SelectQuery :: condition () , et il ne semble pas autoriser cette syntaxe:

public SelectQuery::condition($field, $value = NULL, $operator = NULL)

Il semble seulement permettre des expressions de comparaison de valeurs. Existe-t-il une autre méthode qui fournit cette syntaxe?

Je regarde des conditions de l'ordre de milliers de valeurs, il semble donc inefficace d'avoir un tas de AND value <> x conditions.

6
user1359

Ce que vous recherchez est SelectQuery :: exist () , malheureusement, il ne semble pas fonctionner avec une "méthode courante" pour construire une telle clause:
Normalement, dans une clause EXISTS, vous placez un JOIN sur des tables en dehors de votre sous-requête comme ceci:

SELECT n.nid
FROM node n
WHERE EXISTS (
  SELECT NULL
  FROM users u
  WHERE u.uid = n.uid
  AND u.status = 0)

Cela renvoie les nœuds des utilisateurs bloqués (oui, il peut être construit facilement sans EXISTS mais c'est à des fins pédagogiques;).

Le problème ici est que la condition exists ne prend pas en charge la "liaison externe", la u.uid = n.uid partie donc vous devez construire une requête complètement indépendante qui n'est pas très efficace à mon humble avis.
Dans Drupal vous écrirez ceci:

$query = db_select('node', 'n')
  ->fields('n', array('nid'));
$subquery = db_select('node', 'n2')
  ->fields('n2', array('nid'))
  ->join('users', 'u', 'n2.uid = u.uid'
  ->condition('u.status', 0);
$query->condition('', $subquery, 'EXISTS');
$result = $query->execute();

Vous pouvez également utiliser db_query () comme vous le faisiez dans Drupal 6 et bien sûr SelectQuery :: notExists () est disponible.

8
tostinni

Un moyen plus simple d'utiliser db_select avec une sous-sélection NOT IN consiste simplement à utiliser

$ query-> où

pour ajouter une condition arbitraire where.

par exemple:

  // 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));  
  $result = $query->countQuery()->execute()->fetchField();
  drupal_set_message($result);
2
David Thomas

En fait, vous pouvez utiliser SelectQuery :: condition () pour créer des sous-sélections comme ceci:

$query = db_select('users', 'u')
  ->fields('u', array('uid'))
  ->condition('u.uid', db_select('users_roles', 'r')->fields('r', array('uid')), 'NOT IN');

Si nous imprimons cette requête en utilisant la fonction dpq () de devel, elle affichera:

SELECT u.uid AS uid
FROM 
{users} u
WHERE  (u.uid NOT IN  (SELECT r.uid AS uid
FROM 
{users_roles} r))

J'espère que ça aide ;-)

2
Jelle

Je crois que cela vous aiderait.

$query->where('n.nid NOT IN (:nids)', array(
    ':nids' => implode(',', $nids)
));
0
Vlad Stratulat