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

Gabung luar kiri bertindak seperti gabung dalam

Kueri mungkin dapat disederhanakan menjadi:

SELECT u.name AS user_name
     , p.name AS project_name
     , tl.created_on::date AS changeday
     , coalesce(sum(nullif(new_value, '')::numeric), 0)
     - coalesce(sum(nullif(old_value, '')::numeric), 0) AS hours
FROM   users             u
LEFT   JOIN (
        tasks            t 
   JOIN fixins           f  ON  f.id = t.fixin_id
   JOIN projects         p  ON  p.id = f.project_id
   JOIN task_log_entries tl ON  tl.task_id = t.id
                           AND  tl.field_id = 18
                           AND (tl.created_on IS NULL OR
                                tl.created_on >= '2013-09-08' AND
                                tl.created_on <  '2013-09-09') -- upper border!
       ) ON t.assignee_id = u.id
WHERE  EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id)
GROUP  BY 1, 2, 3
ORDER  BY 1, 2, 3;

Ini mengembalikan semua pengguna yang pernah memiliki tugas apa pun.
Plus data per proyek dan hari di mana data ada dalam rentang tanggal yang ditentukan di task_log_entries .

Poin utama

  • Fungsi gabungan sum() mengabaikan NULL nilai-nilai. COALESCE() per baris tidak diperlukan lagi segera setelah Anda menyusun kembali perhitungan sebagai selisih dua jumlah:

     ,coalesce(sum(nullif(new_value, '')::numeric), 0) -
      coalesce(sum(nullif(old_value, '')::numeric), 0) AS hours
    

    Namun, jika ada kemungkinan semua kolom pilihan memiliki NULL atau string kosong, bungkus jumlahnya menjadi COALESCE sekali.
    Saya menggunakan numeric bukannya float , alternatif yang lebih aman untuk meminimalkan kesalahan pembulatan.

  • Upaya Anda untuk mendapatkan nilai yang berbeda dari gabungan users dan tasks sia-sia, karena Anda bergabung dengan task sekali lagi lebih jauh ke bawah. Ratakan seluruh kueri untuk membuatnya lebih sederhana dan lebih cepat.

  • Ini referensi posisi hanyalah kenyamanan notasi:

    GROUP BY 1, 2, 3
    ORDER BY 1, 2, 3
    

    ... melakukan hal yang sama seperti pada kueri awal Anda.

  • Untuk mendapatkan date dari timestamp Anda cukup melakukan cast ke date :

    tl.created_on::date AS changeday
    

    Tetapi jauh lebih baik untuk menguji dengan nilai asli di WHERE klausa atau JOIN condition (jika memungkinkan, dan dimungkinkan di sini), sehingga Postgres dapat menggunakan indeks biasa pada kolom (jika tersedia):

     AND (tl.created_on IS NULL OR
          tl.created_on >= '2013-09-08' AND
          tl.created_on <  '2013-09-09')  -- next day as excluded upper border
    

    Perhatikan bahwa literal tanggal diubah menjadi timestamp di 00:00 hari ini pada waktu Anda saat ini zona . Anda harus memilih berikutnya hari dan kecualikan itu sebagai batas atas. Atau berikan stempel waktu yang lebih eksplisit seperti '2013-09-22 0:0 +2':: timestamptz . Lebih lanjut tentang mengecualikan batas atas:

  • Untuk kebutuhan every user who has ever been assigned to a task tambahkan WHERE klausa:

    WHERE EXISTS (SELECT 1 FROM tasks t1 WHERE t1.assignee_id = u.id)
    
  • Yang terpenting :LEFT [OUTER] JOIN mempertahankan semua baris di sebelah kiri gabungan. Menambahkan WHERE klausa di kanan tabel dapat membatalkan efek ini. Sebagai gantinya, pindahkan ekspresi filter ke JOIN klausa. Penjelasan lebih lanjut di sini:

  • Kurung dapat digunakan untuk memaksa urutan tabel bergabung. Jarang diperlukan untuk kueri sederhana, tetapi sangat berguna dalam kasus ini. Saya menggunakan fitur ini untuk bergabung dengan task , fixins , projects dan task_log_entries sebelum menggabungkan semuanya ke users - tanpa subkueri.

  • Alias ​​tabel membuat penulisan kueri yang rumit menjadi lebih mudah.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Buat batasan unik dengan kolom nol

  2. Pilih nomor baris di postgres

  3. Bagaimana cara mengimpor tabel dengan nilai yang hilang?

  4. kebuntuan postgresql

  5. Cara memperbarui baris dua tabel yang memiliki batasan kunci asing