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;

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.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.