Quelle est la différence entre INet ANYopérateur dans PostgreSQL?
Le mécanisme de travail des deux semble être le même. Quelqu'un peut-il expliquer cela avec un exemple?
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:
"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 literalSELECT*FROM tbl WHERENOT(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:
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
ANYne 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:
Réponses:
(Ni un "opérateur",
IN
niANY
un "opérateur". Une "construction" ou un "élément de syntaxe".)Logiquement , citant le manuel :
Mais il existe deux variantes de syntaxe
IN
et deux variantes deANY
. Détails:IN
prendre un ensemble équivaut à= ANY
prendre 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
ANY
construction prend un tableau (doit être un type de tableau réel), tandis que la deuxième variante deIN
prend 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()
mais utilisé avecin
ANY
est plus polyvalentLa
ANY
construction est beaucoup plus polyvalente, car elle peut être combinée avec divers opérateurs, pas seulement=
. Exemple:Pour un grand nombre de valeurs, fournir un ensemble de meilleures échelles pour chacune:
En relation:
Inversion / opposé / exclusion
"Rechercher les lignes où se
id
trouve dans le tableau donné":Inversion: « Trouver les lignes où
id
est pas dans le tableau »: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 NULL
ne transmettent aucune de ces expressions. Pour inclure desNULL
valeurs en plus:la source
SELECT * from mytable where id in (1, 2, 3)
donnera toujours les mêmes lignes queSELECT * from mytable where id = ANY('{1, 2, 3}')
, même si elles peuvent potentiellement avoir des plans de requête différents.ANY
ne peut pas être combiné avec l'!=
opérateur. Je ne pense pas que ce soit documenté, mais ceselect * from foo where id != ANY (ARRAY[1, 2])
n'est pas la même chose queselect * 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.ANY
peut ê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.)NULL
valeurs? CelaWHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;
fonctionnerait-il aussi bien?(id = ...) IS NOT TRUE
fonctionne carid = ...
évalue uniquementTRUE
s'il y a une correspondance réelle. RésultatsFALSE
ouNULL
passer 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;
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:
D'autre part:
Seul l'
IN
opérateur autorise une liste simple:Présumer qu'ils sont exactement les mêmes m'a surpris à plusieurs reprises lorsque j'ai oublié que
ANY
cela ne fonctionne pas avec les listes.la source