IN vs ANY-Operator in PostgreSQL

Antworten:

155

(Weder INnoch ANYist ein "Operator". Ein "Konstrukt" oder "Syntaxelement".)

Logisch , zitiert das Handbuch :

INist äquivalent zu = ANY.

Es gibt jedoch zwei Syntaxvarianten von INund zwei Varianten von ANY. Einzelheiten:

IN Das Nehmen eines Sets entspricht dem = ANYNehmen eines Sets , wie hier gezeigt:

Aber die zweite Variante von jedem ist nicht gleichbedeutend mit der anderen. Die zweite Variante des ANYKonstrukts verwendet ein Array (muss ein tatsächlicher Array-Typ sein), während die zweite Variante INeine durch Kommas getrennte Liste von Werten verwendet . Dies führt zu unterschiedlichen Einschränkungen bei der Übergabe von Werten und kann in besonderen Fällen auch zu unterschiedlichen Abfrageplänen führen:

ANY ist vielseitiger

Das ANYKonstrukt ist weitaus vielseitiger, da es nicht nur mit verschiedenen Operatoren kombiniert werden kann =. Beispiel:

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

Für eine große Anzahl von Werten ist die Bereitstellung eines Satzes für jeden Wert besser:

Verbunden:

Inversion / Gegenteil / Ausschluss

"Suchen Sie Zeilen, in denen idsich das angegebene Array befindet":

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

Inversion: "Zeilen suchen, die idsich nicht im Array befinden":

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}'));

Alle drei gleichwertig. Der erste mit Array-Konstruktor , die anderen beiden mit Array-Literal . Der Datentyp kann eindeutig aus dem Kontext abgeleitet werden. Andernfalls kann eine explizite Besetzung erforderlich sein, wie z '{1,2}'::int[].

Zeilen mit übergeben id IS NULLkeinen dieser Ausdrücke. Um NULLWerte zusätzlich aufzunehmen:

SELECT * FROM tbl WHERE (id = ANY ('{1, 2}')) IS NOT TRUE;
Erwin Brandstetter
quelle
4
Es wäre schön, explizit zu verdeutlichen, dass die Ergebnisse der zweiten Varianten immer gleich sein werden. Ich bin mir zu 99% sicher, dass dies tatsächlich der Fall ist, aber die Antwort scheint es nicht zu sagen. SELECT * from mytable where id in (1, 2, 3)Dies bedeutet, dass immer dieselben Zeilen wie angezeigt werden SELECT * from mytable where id = ANY('{1, 2, 3}'), auch wenn sie möglicherweise unterschiedliche Abfragepläne haben.
KPD
1
ANY kann nicht mit dem !=Bediener kombiniert werden. Ich denke nicht, dass es dokumentiert ist, aber es select * from foo where id != ANY (ARRAY[1, 2])ist nicht dasselbe wie select * from foo where id NOT IN (1, 2). Funktioniert dagegen select * from foo where NOT (id = ANY (ARRAY[1, 2]))wie erwartet.
Qris
1
@qris: ANYkann mit dem !=Operator kombiniert werden. Aber es steckt noch mehr dahinter. Ich habe oben ein Kapitel hinzugefügt. (Beachten Sie, dass dies <>der Operator in Standard-SQL ist - obwohl dies !=auch in Postgres akzeptiert wird.)
Erwin Brandstetter
Wie funktioniert die letzte Version, die NULLWerte enthält ? Würde WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;genauso gut funktionieren?
dvtan
1
@dvtan: (id = ...) IS NOT TRUEfunktioniert, weil id = ...nur ausgewertet wird, TRUEob eine tatsächliche Übereinstimmung vorliegt . Ergebnisse FALSEoder NULLbestehen Sie unseren Test. Siehe: stackoverflow.com/a/23767625/939860 . Ihr hinzugefügter Ausdruck testet auf etwas anderes. Dies wäre gleichwertigWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Erwin Brandstetter
3

Es gibt zwei offensichtliche Punkte sowie die Punkte in der anderen Antwort:

  • Sie sind bei Verwendung von Unterabfragen genau gleichwertig:

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

Andererseits:

  • Nur der INOperator erlaubt eine einfache Liste:

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

Die Annahme, dass sie genau gleich sind, hat mich mehrmals überrascht, als ich vergaß, dass ANYdies mit Listen nicht funktioniert.

Manngo
quelle