IN vs QUALSIASI operatore in PostgreSQL


Risposte:


158

(Né INANYè un "operatore". Un "costrutto" o un "elemento di sintassi".)

Logicamente , citando il manuale :

INè equivalente a = ANY.

Ma ci sono due varianti di sintassiIN e due varianti di ANY. Dettagli:

IN prendere un set equivale a = ANYprendere un set , come dimostrato qui:

Ma la seconda variante di ciascuna non è equivalente all'altra. La seconda variante del ANYcostrutto accetta un array (deve essere un tipo di array effettivo), mentre la seconda variante di INaccetta un elenco di valori separati da virgole . Ciò porta a diverse restrizioni nel passaggio di valori e può anche portare a diversi piani di query in casi speciali:

ANY è più versatile

La ANYstruttura è molto più versatile, in quanto può essere combinata con vari operatori, non solo =. Esempio:

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

Per un numero elevato di valori, fornire un set scala meglio per ciascuno:

Relazionato:

Inversione / opposto / esclusione

"Trova le righe in cui si idtrova nella matrice data":

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

Inversione: "Trova righe dove nonid è nell'array":

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

Tutti e tre equivalenti. Il primo con il costruttore di array , gli altri due con il letterale di array . Il tipo di dati può essere derivato dal contesto in modo univoco. Altrimenti, potrebbe essere richiesto un cast esplicito, come '{1,2}'::int[].

Le righe con id IS NULLnon superano nessuna di queste espressioni. Per includere NULLvalori aggiuntivi:

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

4
Sarebbe bello chiarire esplicitamente che i risultati delle seconde varianti saranno sempre gli stessi. Sono sicuro al 99% che sia effettivamente così, ma la risposta non sembra affermarlo. Ciò significa che SELECT * from mytable where id in (1, 2, 3)risulterà sempre nelle stesse righe di SELECT * from mytable where id = ANY('{1, 2, 3}'), anche se potenzialmente potrebbero avere piani di query diversi.
KPD

1
ANY non è cumulabile con l' !=operatore. Non credo sia documentato, ma select * from foo where id != ANY (ARRAY[1, 2])non è lo stesso di select * from foo where id NOT IN (1, 2). D'altra parte, select * from foo where NOT (id = ANY (ARRAY[1, 2]))funziona come previsto.
qris

1
@qris: ANYpuò essere combinato con l' !=operatore. Ma c'è di più. Ho aggiunto un capitolo sopra. (Si noti che <>è l'operatore in SQL standard, sebbene !=sia accettato anche in Postgres.)
Erwin Brandstetter

Come funziona l'ultima versione che include i NULLvalori? Funzionerebbe WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;altrettanto bene?
dvtan il

1
@dvtan: (id = ...) IS NOT TRUEfunziona perché id = ...valuta solo TRUEse esiste una corrispondenza effettiva. Risultati FALSEo NULLsupera il nostro test. Vedi: stackoverflow.com/a/23767625/939860 . La tua espressione aggiunta verifica qualcos'altro. Sarebbe equivalenteWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Erwin Brandstetter

3

Ci sono due punti ovvi, così come i punti nell'altra risposta:

  • Sono esattamente equivalenti quando si utilizzano query secondarie:

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

D'altro canto:

  • Solo l' INoperatore consente un semplice elenco:

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

Presumere che siano esattamente gli stessi mi ha colto di sorpresa diverse volte quando ANYho dimenticato che non funziona con le liste.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.