Ale drugi wariant każdego z nich nie jest równoważny z drugim. Drugi wariant ANYkonstrukcji przyjmuje tablicę (musi być rzeczywistym typem tablicy), podczas gdy drugi wariant INprzyjmuje listę wartości oddzielonych przecinkami . Prowadzi to do różnych ograniczeń w przekazywaniu wartości i może również prowadzić do różnych planów zapytań w szczególnych przypadkach:
„Znajdź wiersze, w których idznajduje się podana tablica”:
SELECT*FROM tbl WHERE id =ANY(ARRAY[1,2]);
Inwersja: „Znajdź wiersze, których nieid ma w tablicy”:
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}'));
Wszystkie trzy równoważne. Pierwsza z konstruktorem tablicy , pozostałe dwie z literałem tablicowym . Typ danych można jednoznacznie wyprowadzić z kontekstu. W przeciwnym razie może być wymagana wyraźna obsada, na przykład '{1,2}'::int[].
Wiersze z id IS NULLnie przechodzą żadnego z tych wyrażeń. Aby NULLdodatkowo uwzględnić wartości:
Byłoby miło wyraźnie wyjaśnić, że wyniki drugiego wariantu zawsze będą takie same. Jestem w 99% pewien, że tak jest, ale odpowiedź nie wydaje się tego określać. Oznacza to, że SELECT * from mytable where id in (1, 2, 3)zawsze będą powodować te same wiersze, co SELECT * from mytable where id = ANY('{1, 2, 3}'), nawet jeśli potencjalnie mogą mieć różne plany zapytań.
KPD
1
ANYnie można łączyć z !=operatorem. Myślę, że nie jest to udokumentowane, ale select * from foo where id != ANY (ARRAY[1, 2])to nie to samo, co select * from foo where id NOT IN (1, 2). Z drugiej strony select * from foo where NOT (id = ANY (ARRAY[1, 2]))działa zgodnie z oczekiwaniami.
qris,
1
@qris: ANYmożna łączyć z !=operatorem. Ale to nie wszystko. Dodałem rozdział powyżej. (Zauważ, że <>jest to operator w standardowym SQL - choć !=jest również akceptowany w Postgres.)
Erwin Brandstetter,
Jak działa ostatnia wersja zawierająca NULLwartości? Działałby WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;równie dobrze?
dvtan
1
@dvtan: (id = ...) IS NOT TRUEdziała, ponieważ wartościowane są id = ...tylko TRUEwtedy, gdy istnieje rzeczywiste dopasowanie. Wyniki FALSElub NULLzdaj nasz test. Zobacz: stackoverflow.com/a/23767625/939860 . Twoje dodane wyrażenie sprawdza coś innego. To byłoby równoważneWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Erwin Brandstetter
3
Istnieją dwa oczywiste punkty, a także punkty w drugiej odpowiedzi:
Są dokładnie równoważne podczas korzystania z zapytań podrzędnych:
Odpowiedzi:
(Ani „operator”,
IN
aniANY
„ nie jest”. „Konstrukcja” lub „element składni”).Logicznie , cytując instrukcję :
Ale istnieją dwa warianty składniowe z
IN
i dwa wariantyANY
. Detale:IN
zabranie zestawu jest równoznaczne z= ANY
wzięciem zestawu , jak pokazano tutaj:Ale drugi wariant każdego z nich nie jest równoważny z drugim. Drugi wariant
ANY
konstrukcji przyjmuje tablicę (musi być rzeczywistym typem tablicy), podczas gdy drugi wariantIN
przyjmuje listę wartości oddzielonych przecinkami . Prowadzi to do różnych ograniczeń w przekazywaniu wartości i może również prowadzić do różnych planów zapytań w szczególnych przypadkach:=any()
ale używany zin
ANY
jest bardziej wszechstronnyANY
Konstrukcja jest bardziej uniwersalny, ponieważ mogą one być połączone z różnymi operatorami, nie tylko=
. Przykład:W przypadku dużej liczby wartości zapewnienie zestawu skal dla każdej z nich jest lepsze:
Związane z:
Inwersja / przeciwieństwo / wykluczenie
„Znajdź wiersze, w których
id
znajduje się podana tablica”:Inwersja: „Znajdź wiersze, których nie
id
ma w tablicy”:Wszystkie trzy równoważne. Pierwsza z konstruktorem tablicy , pozostałe dwie z literałem tablicowym . Typ danych można jednoznacznie wyprowadzić z kontekstu. W przeciwnym razie może być wymagana wyraźna obsada, na przykład
'{1,2}'::int[]
.Wiersze z
id IS NULL
nie przechodzą żadnego z tych wyrażeń. AbyNULL
dodatkowo uwzględnić wartości:źródło
SELECT * from mytable where id in (1, 2, 3)
zawsze będą powodować te same wiersze, coSELECT * from mytable where id = ANY('{1, 2, 3}')
, nawet jeśli potencjalnie mogą mieć różne plany zapytań.ANY
nie można łączyć z!=
operatorem. Myślę, że nie jest to udokumentowane, aleselect * from foo where id != ANY (ARRAY[1, 2])
to nie to samo, coselect * from foo where id NOT IN (1, 2)
. Z drugiej stronyselect * from foo where NOT (id = ANY (ARRAY[1, 2]))
działa zgodnie z oczekiwaniami.ANY
można łączyć z!=
operatorem. Ale to nie wszystko. Dodałem rozdział powyżej. (Zauważ, że<>
jest to operator w standardowym SQL - choć!=
jest również akceptowany w Postgres.)NULL
wartości? DziałałbyWHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;
równie dobrze?(id = ...) IS NOT TRUE
działa, ponieważ wartościowane sąid = ...
tylkoTRUE
wtedy, gdy istnieje rzeczywiste dopasowanie. WynikiFALSE
lubNULL
zdaj nasz test. Zobacz: stackoverflow.com/a/23767625/939860 . Twoje dodane wyrażenie sprawdza coś innego. To byłoby równoważneWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Istnieją dwa oczywiste punkty, a także punkty w drugiej odpowiedzi:
Są dokładnie równoważne podczas korzystania z zapytań podrzędnych:
Z drugiej strony:
Tylko
IN
operator umożliwia prostą listę:Zakładanie, że są dokładnie takie same, przyłapało mnie kilka razy, kiedy zapominałem, że
ANY
to nie działa w przypadku list.źródło