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

Beberapa panggilan array_agg() dalam satu kueri

DISTINCT sering diterapkan untuk memperbaiki kueri yang busuk dari dalam, dan itu sering kali lambat dan/atau salah. Jangan mengalikan baris untuk memulai, maka Anda tidak perlu memilah duplikat yang tidak diinginkan di akhir.

Bergabung ke beberapa n-tabel ("memiliki banyak") sekaligus mengalikan baris dalam kumpulan hasil. Itu seperti CROSS JOIN atau produk Cartesian melalui proxy :

  • Dua SQL LEFT JOIN menghasilkan hasil yang salah

Ada berbagai cara untuk menghindari kesalahan ini.

Agregat dulu, gabung nanti

Secara teknis, kueri berfungsi selama Anda bergabung ke satu tabel dengan beberapa baris sekaligus sebelum Anda menggabungkan:

SELECT e.id, e.name, e.age, e.streets, arrag_agg(wd.day) AS days
FROM  (
   SELECT e.id, e.name, e.age, array_agg(ad.street) AS streets
   FROM   employees e 
   JOIN   address  ad ON ad.employeeid = e.id
   GROUP  BY e.id    -- id enough if it is defined PK
   ) e
JOIN   workingdays wd ON wd.employeeid = e.id
GROUP  BY e.id, e.name, e.age;

Sebaiknya sertakan kunci utama id dan GROUP BY itu, karena name dan age belum tentu unik. Anda dapat menggabungkan dua karyawan secara tidak sengaja.

Tetapi Anda dapat menggabungkan dalam subkueri sebelum Anda bergabung, itu lebih baik kecuali Anda memilih WHERE ketentuan pada employees :

SELECT e.id, e.name, e.age, ad.streets, arrag_agg(wd.day) AS days
FROM   employees e 
JOIN  (
   SELECT employeeid, array_agg(ad.street) AS streets
   FROM   address
   GROUP  BY 1
   ) ad ON ad.employeeid = e.id
JOIN   workingdays wd ON e.id = wd.employeeid
GROUP  BY e.id, e.name, e.age, ad.streets;

Atau gabungkan keduanya:

SELECT name, age, ad.streets, wd.days
FROM   employees e 
JOIN  (
   SELECT employeeid, array_agg(ad.street) AS streets
   FROM   address
   GROUP  BY 1
   ) ad ON ad.employeeid = e.id
JOIN  (
   SELECT employeeid, arrag_agg(wd.day) AS days
   FROM   workingdays
   GROUP  BY 1
   ) wd ON wd.employeeid = e.id;

Yang terakhir biasanya lebih cepat jika Anda mengambil semua atau sebagian besar dari baris dalam tabel dasar.

Perhatikan bahwa menggunakan JOIN dan bukan LEFT JOIN menghapus karyawan dari hasil yang tidak memiliki alamat atau tidak ada hari kerja. Itu mungkin atau mungkin tidak dimaksudkan. Beralih ke LEFT JOIN untuk mempertahankan semua karyawan dalam hasilnya.

Subkueri terkait / LATERAL bergabung

Untuk pilihan kecil , saya akan mempertimbangkan subkueri yang berkorelasi sebagai gantinya:

SELECT name, age
    , (SELECT array_agg(street) FROM address WHERE employeeid = e.id) AS streets
    , (SELECT arrag_agg(day) FROM workingdays WHERE employeeid = e.id) AS days
FROM   employees e
WHERE  e.namer = 'peter';  -- very selective

Atau, dengan Postgres 9.3 atau yang lebih baru, Anda dapat menggunakan LATERAL bergabung untuk itu:

SELECT e.name, e.age, a.streets, w.days
FROM   employees e
LEFT   JOIN LATERAL (
   SELECT array_agg(street) AS streets
   FROM   address
   WHERE  employeeid = e.id
   GROUP  BY 1
   ) a ON true
LEFT   JOIN LATERAL (
   SELECT array_agg(day) AS days
   FROM   workingdays
   WHERE  employeeid = e.id
   GROUP  BY 1
   ) w ON true
WHERE  e.name = 'peter';  -- very selective
  • Apa perbedaan antara LATERAL dan subquery di PostgreSQL?

Salah satu kueri mempertahankan semua karyawan dalam hasilnya.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Apakah desain yang buruk untuk menggunakan array dalam database?

  2. Menghasilkan kolom secara dinamis di PostgreSQL

  3. Haruskah saya menentukan INDEX dan UNIQUE INDEX?

  4. Bagaimana saya bisa menghapus semua tabel dalam database PostgreSQL?

  5. Tips Menyimpan Cadangan PostgreSQL di Google Cloud (GCP)