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;

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.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.