Periksa apakah ada nilai dalam array Postgres

196

Menggunakan Postgres 9.0, saya perlu cara untuk menguji apakah ada nilai dalam array yang diberikan. Sejauh ini saya datang dengan sesuatu seperti ini:

select '{1,2,3}'::int[] @> (ARRAY[]::int[] || value_variable::int)

Tapi saya terus berpikir harus ada cara yang lebih sederhana untuk ini, saya tidak bisa melihatnya. Ini tampaknya lebih baik:

select '{1,2,3}'::int[] @> ARRAY[value_variable::int]

Saya yakin ini sudah cukup. Tetapi jika Anda memiliki cara lain untuk melakukannya, silakan bagikan!

Mike Starov
sumber

Jawaban:

323

Lebih sederhana dengan ANYkonstruk:

SELECT value_variable = ANY ('{1,2,3}'::int[])

Operan kanan ANY(antara tanda kurung) dapat berupa himpunan (hasil dari subquery, misalnya) atau array . Ada beberapa cara untuk menggunakannya:

Penting perbedaan: (operator Array <@, @>, &&. Et al) mengharapkan berbagai jenis sebagai operan dan dukungan GIN atau indeks inti dalam distribusi standar PostgreSQL, sedangkan ANYkonstruk mengharapkan elemen tipe sebagai kiri operan dan tidak mendukung indeks tersebut. Contoh:

Semua ini tidak berfungsi untuk NULLelemen. Untuk menguji NULL:

Erwin Brandstetter
sumber
Terima kasih. Pasti melewatkan bagian manual itu. Ini sangat bagus. Ini memiliki efek samping dari casting otomatis. Contoh: SELECT 1 :: smallint = ANY ('{1,2,3}' :: int []) berfungsi. Pastikan untuk menempatkan ANY () di sisi kanan ekspresi.
Mike Starov
Terima kasih atas jawabannya. Punya masalah di mana kueri saya berfungsi pada lokal, tetapi di heroku melempar pesan ini ANY/ALL (array) requires array on right side, tambah ::int[]melakukan pesona.
kinduff
where S.employee_id <@ ANY ('"+ employeeIDsArray +"' :: int []) Ini mengembalikan PSQLException: ERROR: nilai dimensi yang hilang
Ramprasad
3
Meskipun ini adalah pertanyaan dinosaurus di tahun-tahun internet, orang lambat seperti saya harus dibuat sadar yang 'something' = ANY(some_array)juga dapat digunakan dalam WHEREklausa. Untuk alasan yang hanya diketahui Crom, saya telah menghabiskan empat tahun terakhir berpikir bahwa saya tidak dapat menggunakan pembanding array dalam WHEREklausa. Hari-hari itu hilang sekarang. (Saya dijatuhkan di kepala saya sebagai seorang anak, jadi mungkin itu hanya saya).
GT.
1
@ GT: Intinya: ekspresi apa pun boolean bekerja di WHEREklausa - Crom bersedia.
Erwin Brandstetter
90

Perhatikan jebakan yang saya hadapi: Saat memeriksa apakah nilai tertentu tidak ada dalam array, Anda seharusnya tidak melakukannya:

SELECT value_variable != ANY('{1,2,3}'::int[])

tapi gunakan

SELECT value_variable != ALL('{1,2,3}'::int[])

sebagai gantinya.

pembunuhan
sumber
2
Jenis negatif ganda; perhatikan dia menggunakan ALLvsANY
vol7ron
43
SELECT NOT value_variable = ANY('{1,2,3}'::int[])mungkin lebih mudah dibaca
Ondřej Bouda
28

tetapi jika Anda memiliki cara lain untuk melakukannya silakan bagikan.

Anda dapat membandingkan dua array. Jika salah satu nilai dalam array kiri tumpang tindih dengan nilai-nilai dalam array kanan, maka itu mengembalikan true. Ini semacam peretasan, tetapi berhasil.

SELECT '{1}'   && '{1,2,3}'::int[];  -- true
SELECT '{1,4}' && '{1,2,3}'::int[];  -- true
SELECT '{4}'   && '{1,2,3}'::int[];  -- false
  • Di kueri pertama dan kedua, nilainya 1berada di array yang benar
  • Perhatikan bahwa kueri kedua adalah true, meskipun nilainya 4tidak terkandung dalam array yang benar
  • Untuk kueri ketiga, tidak ada nilai di larik kiri (yaitu, 4) berada di larik kanan, sehingga mengembalikanfalse
vol7ron
sumber
bagaimana saya bisa mencari kolom dari tabel lain untuk memiliki nilai dalam array? mis. pilih * dari bir tempat style_id masuk (pilih preferensi dari pengguna yang id = 1) membatasi 1; style_id adalah tipe data integer; preferensi adalah bilangan bulat [] Saya mendapatkan galat ini KESALAHAN: operator tidak ada: integer = integer [] LINE 1: select * from beers di mana style_id in (pilih preferensi untuk ... ^ PETUNJUK: Tidak ada operator yang cocok dengan nama dan tipe argumen yang diberikan Anda mungkin perlu menambahkan cetakan tipe eksplisit
HP
@ HP Ada berbagai cara untuk menyelesaikan pertanyaan itu, Anda harus mengajukan pertanyaan baru
vol7ron
apakah Anda yakin tidak ada pertanyaan? @ vol7ron
HP
@ HP Tidak sama sekali, tetapi komentar adalah untuk komentar tentang pertanyaan atau jawaban; biasanya untuk menambah informasi atau meminta lebih banyak informasi yang tidak ditangani. Anda mengajukan pertanyaan yang tidak terkait dengan jawaban ini. Saya pikir Anda akan lebih beruntung dengan mengajukan pertanyaan Anda sebagai posting baru, bukan di komentar;)
vol7ron
@ HP jika Anda belum mengirimkan pertanyaan, Anda dapat melihat di sini: sqlfiddle.com/#!15/144cd/3 untuk contoh tentang apa yang perlu Anda lakukan - masalah Anda berbeda karena Anda perlu menghilangkan array Anda.
vol7ron
4

unnestbisa digunakan juga. Itu memperluas array ke satu set baris dan kemudian hanya memeriksa nilai yang ada atau tidak sesederhana menggunakan INatau NOT IN.

misalnya

  1. id => uuid

  2. exception_list_ids => uuid []

select * from table where id NOT IN (select unnest(exception_list_ids) from table2)

hal2286
sumber
Iya. Perhatikan bahwa dalam paket kueri saya SELECT UNNEST tidak sebagus = APA SAJA. Saya akan merekomendasikan memeriksa rencana kueri untuk melihat apakah Anda mendapatkan apa yang Anda inginkan / harapkan.
Rob Bygrave
3

Saat mencari keberadaan elemen dalam array, casting yang tepat diperlukan untuk melewatkan parser SQL postgres. Berikut adalah satu contoh permintaan menggunakan array yang berisi operator dalam klausa gabungan:

Untuk kesederhanaan, saya hanya mencantumkan bagian yang relevan:

table1 other_name text[]; -- is an array of text

Bagian bergabung dari SQL ditampilkan

from table1 t1 join table2 t2 on t1.other_name::text[] @> ARRAY[t2.panel::text]

Berikut ini juga berfungsi

on t2.panel = ANY(t1.other_name)

Saya hanya menebak bahwa casting tambahan diperlukan karena parse tidak harus mengambil definisi tabel untuk mengetahui tipe kolom yang tepat. Lainnya harap berkomentar tentang ini.

Kemin Zhou
sumber
1

Hai yang satu berfungsi dengan baik untuk saya, mungkin berguna untuk seseorang

pilih * dari your_table di mana array_column :: text ilike ANY (ARRAY ['% text_to_search%' :: text]);

Dave Kraczo
sumber