IN vs SETIAP operator di PostgreSQL

Jawaban:

158

(Bukan INjuga ANY"operator". Sebuah "konstruksi" atau "elemen sintaks".)

Logikanya , mengutip manual :

INsetara dengan = ANY.

Tapi ada dua varian sintaks dari INdan dua varian ANY. Rincian:

IN mengambil satu set sama dengan = ANYmengambil satu set , seperti yang ditunjukkan di sini:

Namun varian kedua masing-masing tidak setara dengan yang lain. Varian kedua dari ANYkonstruksi tersebut mengambil sebuah larik (harus berupa jenis larik sebenarnya), sedangkan varian kedua dari INmengambil daftar nilai yang dipisahkan koma . Ini mengarah pada batasan yang berbeda dalam meneruskan nilai dan juga dapat mengarah ke rencana kueri yang berbeda dalam kasus khusus:

ANY lebih serbaguna

The ANYmembangun jauh lebih fleksibel, karena dapat dikombinasikan dengan berbagai operator, tidak hanya =. Contoh:

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

Untuk sejumlah besar nilai, memberikan satu set skala yang lebih baik untuk masing-masing:

Terkait:

Pembalikan / kebalikan / pengecualian

"Temukan baris di mana iddalam larik yang diberikan":

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

Pembalikan: "Temukan baris idyang tidak ada dalam 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}'));

Ketiganya setara. Yang pertama dengan konstruktor array , dua lainnya dengan literal array . Tipe data dapat diturunkan dari konteks dengan jelas. Lain, pemeran eksplisit mungkin diperlukan, seperti '{1,2}'::int[].

Baris dengan id IS NULLtidak lulus salah satu ekspresi ini. Untuk memasukkan NULLnilai - nilai tambahan:

SELECT * FROM tbl WHERE (id = ANY ('{1, 2}')) IS NOT TRUE;
Erwin Brandstetter
sumber
4
Sebaiknya klarifikasi secara eksplisit bahwa hasil varian kedua akan selalu sama. Saya 99% yakin bahwa kenyataannya memang demikian, tetapi jawabannya tampaknya tidak menyatakannya. Artinya, SELECT * from mytable where id in (1, 2, 3)akan selalu menghasilkan baris yang sama dengan SELECT * from mytable where id = ANY('{1, 2, 3}'), meskipun mungkin memiliki rencana kueri yang berbeda.
KPD
1
ANY tidak bisa digabungkan dengan !=operator. Saya tidak berpikir itu didokumentasikan, tetapi select * from foo where id != ANY (ARRAY[1, 2])tidak sama dengan select * from foo where id NOT IN (1, 2). Di sisi lain, select * from foo where NOT (id = ANY (ARRAY[1, 2]))berfungsi seperti yang diharapkan.
qris
1
@qris: ANYdapat digabungkan dengan !=operator. Tapi ada lebih banyak lagi mengenai hal tersebut. Saya menambahkan bab di atas. (Perhatikan bahwa <>operator dalam SQL standar - meskipun !=diterima juga di Postgres.)
Erwin Brandstetter
Bagaimana cara kerja versi terakhir yang menyertakan NULLnilai? Apakah akan WHERE id = ANY (ARRAY[1, 2]) OR id IS NULL;berhasil dengan baik?
dvtan
1
@dvtan: (id = ...) IS NOT TRUEberfungsi karena id = ...hanya mengevaluasi TRUEjika ada kecocokan aktual. Hasil FALSEatau NULLlulus ujian kami. Lihat: stackoverflow.com/a/23767625/939860 . Ekspresi yang Anda tambahkan menguji sesuatu yang lain. Ini akan setaraWHERE id <> ALL (ARRAY[1, 2]) OR id IS NULL;
Erwin Brandstetter
3

Ada dua poin yang jelas, serta poin-poin dalam jawaban lainnya:

  • Mereka sama persis saat menggunakan sub queri:

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

Di samping itu:

  • Hanya INoperator yang mengizinkan daftar sederhana:

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

Menganggap mereka persis sama telah membuat saya beberapa kali lupa bahwa ANYtidak bekerja dengan daftar.

Manngo
sumber