Postgres TIDAK dalam array

100

Saya menggunakan tipe array asli Postgres, dan mencoba menemukan catatan di mana ID tidak ada dalam ID penerima array.

Saya dapat menemukan di mana mereka DI:

SELECT COUNT(*) FROM messages WHERE (3 = ANY (recipient_ids))

Tapi ini tidak berhasil:

SELECT COUNT(*) FROM messages WHERE (3 != ANY (recipient_ids))
SELECT COUNT(*) FROM messages WHERE (3  = NOT ANY (recipient_ids))

Bagaimana cara yang tepat untuk menguji kondisi ini?

pengguna577808
sumber
apakah WHERE 3 NOT IN recipient_idsbekerja?
Janus Troelsen
1
Catatan terkait: untuk text[]dan int[]array:select not(array[1,2,3] @> array[3]);
Steve Peak
3
Tips pro: Jika Anda memeriksa apakah nullkolom berisi atau tidak terdapat dalam array, itu akan selalu mengatakan tidak. Butuh waktu 20 menit untuk men-debug beberapa metode yang berisi untuk sampai pada kesimpulan bahwa Anda tidak dapat memeriksa apakah null terdapat dalam array
André Pena

Jawaban:

139
SELECT COUNT(*) FROM "messages" WHERE NOT (3 = ANY (recipient_ids))

Anda selalu dapat meniadakan WHERE (condition)denganWHERE NOT (condition)

Frank Farmer
sumber
2
@aschyiel - Anda mungkin ingin beralih kembali ke ANYalih-alih INsaat daftar recipient_idsinput Anda bertambah: stackoverflow.com/questions/1009706/…
derekm
41

Anda dapat memutarnya sedikit dan mengatakan "3 tidak sama dengan semua ID":

where 3 != all (recipient_ids)

Dari manual yang bagus :

9.21.4. SEMUA (larik)

expression operator ALL (array expression)

Sisi kanan adalah ekspresi dalam tanda kurung, yang harus menghasilkan nilai array. Ekspresi sebelah kiri dievaluasi dan dibandingkan dengan setiap elemen larik menggunakan operator yang ditentukan , yang harus menghasilkan hasil Boolean. Hasil dari ALLadalah "benar" jika semua perbandingan menghasilkan benar (termasuk kasus di mana array memiliki elemen nol). Hasilnya adalah "salah" jika ditemukan hasil yang salah.

mu terlalu pendek
sumber
ini tidak benar-benar menjelaskan mengapa anytidak berhasil dalam kasus ini
seanlinsley
Ini harus diterima karena menjelaskan alasannya dengan benar. PS Anda juga dapat menemukan anydan alldi doc postgres, yang mengatakan: " x <> ANY (a,b,c) setara dengan x <> a OR <> b OR x <> c". ref: postgresqltutorial.com/postgresql-any postgresqltutorial.com/postgresql-all
Tyler Temp
19

Menambah ALL/ANYJawaban

Saya lebih suka semua solusi yang menggunakan allatau anyuntuk mencapai hasil, menghargai catatan tambahan (misalnya tentang NULL s). Sebagai tambahan lainnya, berikut adalah cara untuk memikirkan operator tersebut.

Anda dapat menganggapnya sebagai operator hubung singkat :

  • all(array)menelusuri semua nilai dalam larik, membandingkan masing-masing dengan nilai referensi menggunakan operator yang disediakan. Begitu perbandingan menghasilkan false, proses berakhir dengan salah, jika tidak benar. (Sebanding dengan logika hubung singkat and.)
  • any(array)menelusuri semua nilai dalam larik, membandingkan masing-masing dengan nilai referensi menggunakan operator yang disediakan. Segera setelah hasil perbandingan true, proses berakhir dengan benar, sebaliknya salah. (Sebanding dengan logika hubung singkat or.)

Inilah sebabnya mengapa 3 <> any('{1,2,3}')tidak menghasilkan hasil yang diinginkan: Proses membandingkan 3 dengan 1 untuk ketidaksetaraan, yang benar, dan segera mengembalikan benar. Nilai tunggal dalam larik yang berbeda dari 3 sudah cukup untuk membuat seluruh ketentuan menjadi benar. Angka 3 pada posisi larik terakhir adalah prob. tidak pernah dipakai.

3 <> all('{1,2,3}')di sisi lain memastikan semua nilai tidak sama 3. Ini akan berjalan melalui semua perbandingan yang menghasilkan true hingga elemen yang menghasilkan false (yang terakhir dalam kasus ini), untuk mengembalikan false sebagai hasil keseluruhan. Inilah yang diinginkan OP.

ThomasH
sumber
12

not (3 = any(recipient_ids))?

Markus Mikkolainen
sumber
Terima kasih, saya telah menggunakan 3 <> ANY(ARRAY[1,2,3,4]). Seharusnya bekerja seperti itu: \
yeyo
12

Sebuah pembaharuan:

pada postgres 9.3,

Anda dapat menggunakan NOTbersama-sama dengan @> (berisi operator) untuk mencapai ini juga.

YAITU.

SELECT COUNT(*) FROM "messages" WHERE NOT recipient_ids @> ARRAY[3];

Ayam jantan
sumber
12

Waspadalah terhadap NULL

Keduanya ALL:

(some_value != ALL(some_array))

Dan ANY:

NOT (some_value = ANY(some_array))

Akan bekerja selama some_arraytidak null. Jika array mungkin null, maka Anda harus memperhitungkannya dengan coalesce (), misalnya

(some_value != ALL(coalesce(some_array, array[]::int[])))

Atau

NOT (some_value = ANY(coalesce(some_array, array[]::int[])))

Dari dokumen :

Jika ekspresi array menghasilkan array nol, hasil ANY akan menjadi nol

Jika ekspresi array menghasilkan array nol, hasil ALL akan menjadi nol

isapir
sumber
3

Perhatikan bahwa operator ANY / ALL tidak akan bekerja dengan indeks array. Jika indeks dalam pikiran:

SELECT COUNT(*) FROM "messages" WHERE 3 && recipient_ids

dan negatif:

SELECT COUNT(*) FROM "messages" WHERE NOT (3 && recipient_ids)

Indeks kemudian dapat dibuat seperti:

CREATE INDEX recipient_ids_idx on tableName USING GIN(recipient_ids)
jamming james
sumber
Tidak seperti jawaban lain, jawaban ini sebenarnya menggunakan operator tumpang tindih array PostgreSQL. &&
Ceiling Gecko
6
Ini tidak akan berfungsi seperti yang tertulis. Operator larik seperti && dan @> mengharuskan kedua elemen menjadi larik, sedangkan 3 bukan. Agar ini bekerja, query akan perlu ditulis sebagai: SELECT COUNT(*) FROM "messages" WHERE ARRAY[3] && recipient_ids.
Dologan