Postgres PAS dans le tableau


96

J'utilise le type de tableau natif de Postgres et j'essaie de trouver les enregistrements où l'ID n'est pas dans les ID de destinataire du tableau.

Je peux trouver où ils sont DANS:

SELECT COUNT(*) FROM messages WHERE (3 = ANY (recipient_ids))

Mais cela ne fonctionne pas:

SELECT COUNT(*) FROM messages WHERE (3 != ANY (recipient_ids))
SELECT COUNT(*) FROM messages WHERE (3  = NOT ANY (recipient_ids))

Quelle est la bonne façon de tester cette condition?


ça WHERE 3 NOT IN recipient_idsmarche?
Janus Troelsen

1
Note connexe: comme pour text[]et int[]tableau:select not(array[1,2,3] @> array[3]);
Steve Peak

3
Conseil de pro: Si vous vérifiez si une nullcolonne est contenue ou non dans un tableau, elle dira toujours non. Il m'a fallu environ 20 minutes de débogage de plusieurs méthodes contenant pour arriver à la conclusion que vous ne pouvez pas vérifier si null est contenu dans un tableau
André Pena

Réponses:


136
SELECT COUNT(*) FROM "messages" WHERE NOT (3 = ANY (recipient_ids))

Vous pouvez toujours nier WHERE (condition)avecWHERE NOT (condition)


2
@aschyiel - Vous voudrez peut-être revenir à ANYau lieu de au INfur et à mesure que votre recipient_idsliste d'entrées s'allonge: stackoverflow.com/questions/1009706/…
derekm

39

Vous pouvez le retourner un peu et dire "3 n'est pas égal à tous les ID":

where 3 != all (recipient_ids)

Du manuel fin :

9.21.4. TOUS (tableau)

expression operator ALL (array expression)

Le côté droit est une expression entre parenthèses, qui doit produire une valeur de tableau. L'expression de gauche est évaluée et comparée à chaque élément du tableau à l'aide de l' opérateur donné , qui doit donner un résultat booléen. Le résultat de ALLest "vrai" si toutes les comparaisons donnent vrai (y compris le cas où le tableau ne contient aucun élément). Le résultat est "faux" si un résultat faux est trouvé.


cela n'explique pas vraiment pourquoi anyne fonctionne pas dans ce cas
seanlinsley

Cela doit être accepté car il explique correctement la raison. PS vous pouvez également trouver anyet allsur postgres doc, qui dit: " x <> ANY (a,b,c) équivaut à x <> a OR <> b OR x <> c". ref: postgresqltutorial.com/postgresql-any postgresqltutorial.com/postgresql-all
Tyler Temp

19

Augmenter les ALL/ANYréponses

Je préfère toutes les solutions qui utilisent allou anypour obtenir le résultat, en appréciant les notes supplémentaires (par exemple à propos des NULL ). Comme autre augmentation, voici une façon de penser à ces opérateurs.

Vous pouvez les considérer comme des opérateurs de court-circuit :

  • all(array)parcourt toutes les valeurs du tableau, en les comparant à la valeur de référence à l'aide de l'opérateur fourni. Dès qu'une comparaison aboutit false, le processus se termine par false, sinon true. (Comparable à la logique de court-circuit and.)
  • any(array)parcourt toutes les valeurs du tableau, en les comparant à la valeur de référence à l'aide de l'opérateur fourni. Dès qu'une comparaison aboutit true, le processus se termine par vrai, sinon faux. (Comparable à la logique de court-circuit or.)

C'est pourquoi 3 <> any('{1,2,3}')ne donne pas le résultat souhaité: le processus compare 3 à 1 pour l'inégalité, ce qui est vrai, et renvoie immédiatement vrai. Une seule valeur du tableau différente de 3 suffit pour que la condition entière soit vraie. Le 3 dans la dernière position du tableau est prob. jamais utilisé.

3 <> all('{1,2,3}')d'autre part s'assure que toutes les valeurs ne sont pas égales à 3. Il exécutera toutes les comparaisons qui donnent vrai jusqu'à un élément qui donne faux (le dernier dans ce cas), pour retourner faux comme résultat global. C'est ce que veut l'OP.


12

not (3 = any(recipient_ids))?


Merci, j'utilisais 3 <> ANY(ARRAY[1,2,3,4]). Cela aurait dû fonctionner de cette façon: \
yeyo

11

une mise à jour:

à partir de postgres 9.3,

vous pouvez également utiliser NOTen tandem avec l' @> opérateur (contains) pour y parvenir.

C'EST À DIRE.

SELECT COUNT(*) FROM "messages" WHERE NOT recipient_ids @> ARRAY[3];


11

Méfiez-vous des NULL

Les deux ALL:

(some_value != ALL(some_array))

Et ANY:

NOT (some_value = ANY(some_array))

Cela fonctionnerait tant que ce some_arrayn'est pas nul Si le tableau peut être nul, vous devez en tenir compte avec coalesce (), par exemple

(some_value != ALL(coalesce(some_array, array[]::int[])))

Ou

NOT (some_value = ANY(coalesce(some_array, array[]::int[])))

À partir de la documentation :

Si l'expression de tableau donne un tableau nul, le résultat de ANY sera nul

Si l'expression de tableau donne un tableau nul, le résultat de ALL sera nul


3

Notez que les opérateurs ANY / ALL ne fonctionneront pas avec les index de tableau. Si vous pensez aux index:

SELECT COUNT(*) FROM "messages" WHERE 3 && recipient_ids

et le négatif:

SELECT COUNT(*) FROM "messages" WHERE NOT (3 && recipient_ids)

Un index peut alors être créé comme:

CREATE INDEX recipient_ids_idx on tableName USING GIN(recipient_ids)

Contrairement à d'autres réponses, cette réponse utilise en fait l'opérateur de chevauchement de tableau PostgreSQL. &&
Ceiling Gecko le

6
Cela ne fonctionnera pas comme écrit. Les opérateurs de tableau comme && et @> exigent que les deux éléments soient des tableaux, ce qui n'est pas le cas 3. Pour que cela fonctionne, la requête doit être écrite comme suit SELECT COUNT(*) FROM "messages" WHERE ARRAY[3] && recipient_ids:.
Dologan le
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.