web-dev-qa-db-fra.com

Postgres PAS en tableau

J'utilise le type de tableau natif de Postgres et j'essaie de trouver les enregistrements dont l'ID ne figure pas dans les ID de destinataires du tableau.

Je peux trouver où ils sont dans:

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

Mais ça ne marche 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?

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

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

104
Frank Farmer

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. ALL (tableau)

expression operator ALL (array expression)

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

35
mu is too short

Augmenter les réponses ALL/ANY

Je préfère toutes les solutions qui utilisent all ou any pour obtenir le résultat, en appréciant les notes supplémentaires (par exemple à propos de NULL s ) En tant qu’autre chose, voici une façon de penser à ces opérateurs.

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

  • all(array) passe en revue 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 donne false, le processus se termine par false, sinon vrai. (Comparable à la logique de court-circuit and.)
  • any(array) passe en revue 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 donne true, le processus se termine par true, 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 avec 1 pour l'inégalité, ce qui est vrai et renvoie immédiatement vrai. Une seule valeur dans le tableau différente de 3 est suffisante 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}') quant à lui, s'assure que toutes les valeurs ne sont pas égales à 3. Il exécutera toutes les comparaisons qui donnent élément qui produit false (le dernier dans ce cas), pour retourner false comme résultat global. C'est ce que veut le PO.

11
ThomasH

not (3 = any(recipient_ids))?

9
Markus Mikkolainen

une mise à jour:

à partir de postgres 9.3,

vous pouvez utiliser NOT en tandem avec le @>(contient l'opérateur) pour y parvenir également.

C'EST À DIRE.

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

7
Rooster

Attention aux NULL

Les deux ALL:

(some_value != ALL(some_array))

Et ANY:

NOT (some_value = ANY(some_array))

Travaillerait aussi longtemps que some_array est non nulle. Si le tableau peut être null, vous devez alors en rendre compte avec coalesce (), par exemple.

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

Ou

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

De la docs :

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

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

6
isapir

Notez que les opérateurs ANY/ALL ne fonctionneront pas avec les index de tableau. Si des index sont à l’esprit:

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)
3
jamming james