Vérifier si la valeur existe dans le tableau Postgres

196

En utilisant Postgres 9.0, j'ai besoin d'un moyen de tester si une valeur existe dans un tableau donné. Jusqu'à présent, j'ai trouvé quelque chose comme ça:

select '{1,2,3}'::int[] @> (ARRAY[]::int[] || value_variable::int)

Mais je n'arrête pas de penser qu'il devrait y avoir un moyen plus simple, je ne peux pas le voir. Cela semble mieux:

select '{1,2,3}'::int[] @> ARRAY[value_variable::int]

Je pense que cela suffira. Mais si vous avez d'autres moyens de le faire, partagez-le!

Mike Starov
la source

Réponses:

323

Plus simple avec la ANYconstruction:

SELECT value_variable = ANY ('{1,2,3}'::int[])

L'opérande droit de ANY(entre parenthèses) peut être un ensemble (résultat d'une sous-requête, par exemple) ou un tableau . Il existe plusieurs façons de l'utiliser:

Important différence: (opérateurs de tableaux <@, @>, &&. Et al) attendre tableau types comme opérandes et GIN de soutien ou indices GiST dans la distribution standard de PostgreSQL, alors que la ANYconstruction attend un élément type que gauche opérande et ne prend pas en charge ces indices. Exemple:

Rien de tout cela ne fonctionne pour les NULLéléments. Pour tester NULL:

Erwin Brandstetter
la source
Merci. Doit avoir sauté cette partie du manuel. Cela fonctionne très bien. Il a un effet secondaire de la coulée automatique. Ex: SELECT 1 :: smallint = ANY ('{1,2,3}' :: int []) fonctionne. Assurez-vous simplement de mettre ANY () sur le côté droit de l'expression.
Mike Starov
Merci d'avoir répondu. J'ai un problème où ma requête fonctionnait en local, mais dans Heroku jetait ce message ANY/ALL (array) requires array on right side, l'ajout de a ::int[]fait le charme.
kinduff
où S.employee_id <@ ANY ('"+ employeeIDsArray +"' :: int []) Ceci renvoie PSQLException: ERROR: valeur de dimension manquante
Ramprasad
3
Bien que ce soit une question de dinosaure dans les années Internet, les gens lents comme moi devraient être informés que cela 'something' = ANY(some_array)peut également être utilisé dans une WHEREclause. Pour des raisons connues uniquement de Crom, j'ai passé les quatre dernières années à penser que je ne pouvais pas utiliser de comparateurs de tableaux dans les WHEREclauses. Ces jours sont révolus maintenant. (J'étais tombé sur la tête quand j'étais enfant, alors c'est peut-être juste moi)
GT.
1
@GT .: L'essentiel: toute boolean expression fonctionne dans la WHEREclause - Crom voulant.
Erwin Brandstetter
90

Méfiez-vous du piège dans lequel je suis entré: lorsque vous vérifiez si une certaine valeur n'est pas présente dans un tableau, vous ne devriez pas faire:

SELECT value_variable != ANY('{1,2,3}'::int[])

mais utilisez

SELECT value_variable != ALL('{1,2,3}'::int[])

au lieu.

Murison
la source
2
Une sorte de double négatif; remarquez son utilisation de ALLvsANY
vol7ron
43
SELECT NOT value_variable = ANY('{1,2,3}'::int[])pourrait être plus lisible
Ondřej Bouda
28

mais si vous avez d'autres façons de le faire, veuillez partager.

Vous pouvez comparer deux tableaux. Si l'une des valeurs du tableau de gauche chevauche les valeurs du tableau de droite, elle renvoie true. C'est un peu hackish, mais ça marche.

SELECT '{1}'   && '{1,2,3}'::int[];  -- true
SELECT '{1,4}' && '{1,2,3}'::int[];  -- true
SELECT '{4}'   && '{1,2,3}'::int[];  -- false
  • Dans la première et la deuxième requête, la valeur 1est dans le bon tableau
  • Notez que la deuxième requête est true, même si la valeur 4n'est pas contenue dans le bon tableau
  • Pour la troisième requête, aucune valeur dans le tableau de gauche (c'est-à-dire 4) n'est dans le tableau de droite, donc il renvoiefalse
vol7ron
la source
comment puis-je rechercher une colonne d'une autre table pour avoir une valeur dans le tableau? par exemple, sélectionnez * parmi les bières où style_id dans (sélectionnez les préférences des utilisateurs où id = 1) limite 1; style_id est un type de données entier; preferences is integer [] J'obtiens cette erreur ERREUR: l'opérateur n'existe pas: integer = integer [] LINE 1: sélectionnez * parmi les bières où style_id dans (sélectionnez les préférences f ... ^ CONSEIL: Aucun opérateur ne correspond au nom et au type d'argument donnés (s). Vous devrez peut-être ajouter des casts de type explicite.
HP
@HP Il existe différentes façons de résoudre cette question, vous devriez poser une nouvelle question
vol7ron
êtes-vous sûr qu'il n'y a pas de question existante? @ vol7ron
HP
@HP Pas du tout, mais les commentaires sont des commentaires concernant une question ou une réponse; généralement pour ajouter plus d'informations ou solliciter plus d'informations qui n'ont pas été traitées. Vous posez une question qui n'est pas liée à cette réponse. Je pense que vous aurez plus de chance en posant votre question dans un nouveau post, pas dans le commentaire;)
vol7ron
@HP si vous n'avez pas posté votre question, vous pouvez voir ici: sqlfiddle.com/#!15/144cd/3 pour un exemple de ce que vous devez faire - votre problème est différent parce que vous devez désnombler votre tableau.
vol7ron
4

unnestpeut également être utilisé. Il étend le tableau à un ensemble de lignes, puis vérifier simplement qu'une valeur existe ou non est aussi simple que d'utiliser INou NOT IN.

par exemple

  1. id => uuid

  2. exception_list_ids => uuid []

select * from table where id NOT IN (select unnest(exception_list_ids) from table2)

pg2286
la source
Oui. Notez que dans mes plans de requête SELECT UNNEST n'est pas aussi bon que = ANY. Je vous recommande de vérifier les plans de requête pour voir si vous obtenez ce que vous voulez / attendez.
Rob Bygrave
3

Lors de la recherche de l'existence d'un élément dans un tableau, une conversion appropriée est requise pour passer l'analyseur SQL de postgres. Voici un exemple de requête utilisant un tableau contenant un opérateur dans la clause de jointure:

Pour simplifier, je ne liste que la partie pertinente:

table1 other_name text[]; -- is an array of text

La partie jointure de SQL affichée

from table1 t1 join table2 t2 on t1.other_name::text[] @> ARRAY[t2.panel::text]

Ce qui suit fonctionne également

on t2.panel = ANY(t1.other_name)

Je suppose juste que le casting supplémentaire est nécessaire car l'analyse n'a pas besoin de récupérer la définition de la table pour déterminer le type exact de la colonne. D'autres s'il vous plaît commenter à ce sujet.

Kemin Zhou
la source
1

Salut celui-là fonctionne bien pour moi, peut-être utile pour quelqu'un

sélectionnez * dans votre_table où array_column :: text ilike ANY (ARRAY ['% text_to_search%' :: text]);

Dave Kraczo
la source