Quelle est la bonne façon d'écrire une requête contenant «NOT IN» à l'aide d'une déclaration de condition?
Ma requête est la suivante:
SELECT DISTINCT nid FROM node WHERE language NOT IN
(SELECT language
FROM languages WHERE language = 'ab');
J'ai essayé quelque chose comme ceci:
$query->condition('n.' . $key, $value, 'not in (select language from
languages where language = $value)');
SELECT nid FROM node WHERE language != 'ab'
?Réponses:
Dans l'exemple spécifique, vous devez simplement écrire la condition comme suit:
Dans le cas générique, où vous devez sélectionner les lignes d'une base de données en fonction des valeurs renvoyées par une sous-requête, vous devez considérer ce qui suit:
"NOT IN" est accepté comme opérateur à partir de
SelectQuery::condition()
. En fait, la requête suivante serait exécutée:Comme indiqué dans les clauses conditionnelles ("Sous-sélections"),
SelectQuery::condition()
accepte également un objet implémentantSelectQueryInterface
comme valeur pour$value
, tel que celui renvoyé pardb_select()
; le problème est qu'en fait, vous pouvez simplement l'utiliser lorsque la valeur de$operator
est égale à"IN"
. Voir Les sous-sélections ne fonctionnent pas dans des conditions DBTNG, sauf lorsqu'elles sont utilisées comme valeur pour IN .La seule façon que je peux voir d'utiliser l'opérateur "NOT IN" avec une sous-requête dans
condition
est de:Exécutez la requête principale en définissant la condition comme dans l'extrait de code suivant
$subquery_result
est le tableau contenant le résultat de la sous-requête.Sinon, vous pourriez utiliser
where()
comme d'autres l'ont dit, qui accepte une chaîne pour la partie de la requête que vous devez ajouter.Gardez à l'esprit que
db_select()
c'est plus lent que celadb_query()
; vous devez utiliser le premier lorsque vous savez que la requête peut être modifiée par d'autres modules. Sinon, si d'autres modules ne sont pas censés utiliserhook_query_alter()
pour modifier votre requête, vous devez utiliserdb_query()
.Dans le cas de l'accès aux nœuds, si vous devez obtenir uniquement les nœuds auxquels un utilisateur a accès, vous devez utiliser
db_select()
et ajouter'node_access'
comme balise de la requête, avecSelectQuery::addTag()
. Par exemple,blog_page_last()
utilise le code suivant.Un code similaire est utilisé par
book_block_view()
.la source
Lors de l'écriture de requêtes complexes, vous devez absolument utiliser à la
db_query()
place dedb_select()
.NOT IN
clause avec une sous-requête avec l'API de base de données Drupal actuelle (c'est un problème connu en cours d'élaboration).db_select()
.db_query()
.Concernant votre requête, je ne sais pas pourquoi vous souhaitez utiliser une sous-requête (sauf si vous avez simplifié votre exemple)? Vous pouvez l'écrire facilement comme ceci:
DISTINCT
n'est pas nécessaire, tout commenid
une clé primaire, elle ne sera donc pas dupliquée.la source
Il y a aussi where () qui permet d'ajouter une condition arbitraire where à la requête.
Exemple:
Comme Keithm l'a mentionné, vous devez utiliser db_select () et addTag ('node_access') lors de la sélection des nœuds qui sont ensuite affichés aux utilisateurs.
la source
Un moyen plus simple d'utiliser db_select avec une sous-sélection NOT IN consiste simplement à utiliser le peu connu
$ query-> où
pour ajouter une condition arbitraire where.
par exemple:
la source
Où $ subquery_values est un tableau de format $ key => $ nid résultant d'une sous-requête
ça fonctionne bien.
la source