Opérateur IN vs ANY dans PostgreSQL


Réponses:


158

(Ni un "opérateur", INni ANYun "opérateur". Une "construction" ou un "élément de syntaxe".)

Logiquement , citant le manuel :

INéquivaut à = ANY.

Mais il existe deux variantes de syntaxeIN et deux variantes de ANY. Détails:

IN prendre un ensemble équivaut à = ANYprendre un ensemble , comme démontré ici:

Mais la deuxième variante de chacun n'est pas équivalente à l'autre. La deuxième variante de la ANYconstruction prend un tableau (doit être un type de tableau réel), tandis que la deuxième variante de INprend une liste de valeurs séparées par des virgules . Cela conduit à différentes restrictions dans la transmission des valeurs et peut également conduire à différents plans de requête dans des cas particuliers:

ANY est plus polyvalent

La ANYconstruction est beaucoup plus polyvalente, car elle peut être combinée avec divers opérateurs, pas seulement =. Exemple:

SELECT 'foo' LIKE ANY('{FOO,bar,%oo%}');

Pour un grand nombre de valeurs, fournir un ensemble de meilleures échelles pour chacune:

En relation:

Inversion / opposé / exclusion

"Rechercher les lignes où se idtrouve dans le tableau donné":

SELECT * FROM tbl WHERE id = ANY (ARRAY[1, 2]);

Inversion: « Trouver les lignes où idest pas dans le tableau »:

SELECT * FROM tbl WHERE id <> ALL (ARRAY[1, 2]);
SELECT * FROM tbl WHERE id <> ALL ('{1, 2}');  -- equivalent array literal
SELECT * FROM tbl WHERE NOT (id = ANY ('{1, 2}'));

Les trois équivalents. Le premier avec un constructeur de tableau , les deux autres avec un littéral de tableau . Le type de données peut être dérivé du contexte sans ambiguïté. Sinon, une distribution explicite peut être requise, comme '{1,2}'::int[].

Les lignes avec id IS NULLne transmettent aucune de ces expressions. Pour inclure des NULLvaleurs en plus:

SELECT * FROM tbl WHERE (id = ANY ('{1, 2}')) IS NOT TRUE;

4
Ce serait bien de préciser explicitement que les résultats des deuxièmes variantes seront toujours les mêmes. Je suis sûr à 99% que c'est effectivement le cas, mais la réponse ne semble pas le dire. Cela signifie que cela SELECT * from mytable where id in (1, 2, 3)donnera toujours les mêmes lignes que SELECT * from mytable where id = ANY('{1, 2, 3}'), même si elles peuvent potentiellement avoir des plans de requête différents.
KPD

1
ANY ne peut pas être combiné avec l' !=opérateur. Je ne pense pas que ce soit documenté, mais ce select * from foo where id != ANY (ARRAY[1, 2])n'est pas la même chose que select * from foo where id NOT IN (1, 2). D'autre part, select * from foo where NOT (id = ANY (ARRAY[1, 2]))fonctionne comme prévu.
qris

1
@qris: ANYpeut être combiné avec l' !=opérateur. Mais il y a plus que cela. J'ai ajouté un chapitre ci-dessus. (Notez que <>c'est l'opérateur en SQL standard - bien qu'il !=soit également accepté dans Postgres.)
Erwin Brandstetter

Comment fonctionne la dernière version qui inclut des NULLvaleurs? Cela WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;fonctionnerait-il aussi bien?
dvtan le

1
@dvtan: (id = ...) IS NOT TRUEfonctionne car id = ...évalue uniquement TRUEs'il y a une correspondance réelle. Résultats FALSEou NULLpasser notre test. Voir: stackoverflow.com/a/23767625/939860 . Votre expression ajoutée teste autre chose. Ce serait équivalentWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Erwin Brandstetter le

3

Il y a deux points évidents, ainsi que les points de l'autre réponse:

  • Ils sont exactement équivalents lors de l'utilisation de sous-requêtes:

    SELECT * FROM table
    WHERE column IN(subquery);
    
    SELECT * FROM table
    WHERE column = ANY(subquery);

D'autre part:

  • Seul l' INopérateur autorise une liste simple:

    SELECT * FROM table
    WHERE column IN(… ,  , …);

Présumer qu'ils sont exactement les mêmes m'a surpris à plusieurs reprises lorsque j'ai oublié que ANYcela ne fonctionne pas avec les listes.

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.