PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

LEFT OUTER JOIN pada kolom array dengan beberapa nilai

Ya, operator tumpang tindih && bisa menggunakan indeks GIN pada array . Sangat berguna untuk kueri yang satu ini untuk menemukan baris dengan orang tertentu (1 ) di antara berbagai aktor:

SELECT * FROM eg_assoc WHERE actors && '{1}'::int[]

Namun , logika kueri Anda adalah sebaliknya, mencari semua orang yang terdaftar dalam array di eg_assoc . Indeks GIN tidak membantu di sini. Kami hanya membutuhkan indeks btree dari PK person.id .

Kueri yang tepat

Dasar-dasar:

Kueri berikut mempertahankan larik asli persis seperti yang diberikan , termasuk kemungkinan elemen duplikat dan urutan elemen asli. Berfungsi untuk array 1-dimensi . Dimensi tambahan dilipat menjadi satu dimensi. Lebih rumit untuk mempertahankan beberapa dimensi (tetapi sangat mungkin):

WITH ORDINALITY di Postgres 9.4 atau lebih baru

SELECT aid, actors
     , ARRAY(SELECT name
             FROM   unnest(e.actors) WITH ORDINALITY a(id, i)
             JOIN   eg_person p USING (id)
             ORDER  BY a.i) AS act_names
     , benefactors
     , ARRAY(SELECT name
             FROM   unnest(e.benefactors) WITH ORDINALITY b(id, i)
             JOIN   eg_person USING (id)
             ORDER  BY b.i) AS ben_names
FROM   eg_assoc e;

LATERAL kueri

Untuk PostgreSQL 9.3+ .

SELECT e.aid, e.actors, a.act_names, e.benefactors, b.ben_names
FROM   eg_assoc e
, LATERAL (
   SELECT ARRAY( SELECT name
                 FROM   generate_subscripts(e.actors, 1) i
                 JOIN   eg_person p ON p.id = e.actors[i]
                 ORDER  BY i)
   ) a(act_names)
, LATERAL (
   SELECT ARRAY( SELECT name
                 FROM   generate_subscripts(e.benefactors, 1) i
                 JOIN   eg_person p ON p.id = e.benefactors[i]
                 ORDER  BY i)
   ) b(ben_names);

db<>fiddle di sini dengan beberapa varian.
Lama sqlfiddle

Detail halus:Jika seseorang tidak ditemukan, itu hanya dijatuhkan. Kedua kueri ini menghasilkan array kosong ('{}' ) jika tidak ada orang yang ditemukan untuk seluruh array. Gaya kueri lainnya akan mengembalikan NULL . Saya menambahkan varian ke biola.

Subkueri terkait

Untuk Postgres 8.4+ (di mana generate_subsrcipts() diperkenalkan):

SELECT aid, actors
     , ARRAY(SELECT name
             FROM   generate_subscripts(e.actors, 1) i
             JOIN   eg_person p ON p.id = e.actors[i]
             ORDER  BY i) AS act_names
     , benefactors
     , ARRAY(SELECT name
             FROM   generate_subscripts(e.benefactors, 1) i
             JOIN   eg_person p ON p.id = e.benefactors[i]
             ORDER  BY i) AS ben_names
FROM   eg_assoc e;

Mungkin masih berkinerja terbaik, bahkan di Postgres 9.3.
The ARRAY konstruktor lebih cepat dari array_agg() . Lihat:

Kueri Anda yang gagal

kueri yang disediakan oleh @a_horse sepertinya untuk melakukan pekerjaan itu, tetapi tidak dapat diandalkan, menyesatkan, berpotensi salah, dan tidak perlu mahal.

  1. Gabung silang proxy karena dua gabungan yang tidak terkait. Sebuah anti-pola licik. Lihat:

    Diperbaiki secara dangkal dengan DISTINCT di array_agg() untuk menghilangkan duplikat yang dihasilkan, tapi itu benar-benar menempatkan lipstik pada babi. Itu juga menghilangkan duplikat dalam aslinya karena saat ini tidak mungkin untuk membedakannya - yang berpotensi salah.

  2. Ekspresi a_person.id = any(eg_assoc.actors) berfungsi , tetapi menghilangkan duplikat dari hasil (terjadi dua kali dalam kueri ini), yang salah kecuali ditentukan.

  3. Urutan elemen larik asli tidak dipertahankan . Ini rumit secara umum. Tapi itu diperparah dalam kueri ini, karena aktor dan dermawan dikalikan dan dibuat berbeda lagi, yang menjamin perintah sewenang-wenang.

  4. Tidak ada alias kolom di bagian luar SELECT menghasilkan nama kolom duplikat, yang membuat beberapa klien gagal (tidak bekerja di biola tanpa alias).

  5. min(actors) dan min(benefactors) tidak berguna. Biasanya orang hanya akan menambahkan kolom ke GROUP BY bukannya palsu-menggabungkan mereka. Tapi eg_assoc.aid adalah kolom PK (mencakup seluruh tabel dalam GROUP BY ), jadi itu bahkan tidak perlu. Hanya actors, benefactors .

Menggabungkan seluruh hasil membuang-buang waktu dan usaha untuk memulai. Gunakan kueri yang lebih cerdas yang tidak mengalikan baris dasar, lalu Anda tidak perlu menggabungkannya kembali.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. psycopg2 setara dengan mysqldb.escape_string?

  2. Bagaimana Anda mendapatkan tampilan 12 hari kerja yang dinamis di Postgresql?

  3. Mewakili Tanggal, Waktu, dan Interval di PostgreSQL

  4. Mengimpor skema xml ke postgres untuk membuat tabel secara otomatis dan kemudian mengisinya dengan file xml?

  5. Bagaimana cara menghapus sejumlah baris tetap dengan penyortiran di PostgreSQL?