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

Bagaimana cara memasukkan data yang hilang untuk beberapa pengelompokan dalam rentang waktu?

Berdasarkan beberapa asumsi (ambiguitas dalam pertanyaan) saya menyarankan:

SELECT upper(trim(t.full_name)) AS teacher
     , m.study_month
     , r.room_code              AS room
     , count(s.room_id)         AS study_count

FROM   teachers t
CROSS  JOIN generate_series(date_trunc('month', now() - interval '12 month')  -- 12!
                          , date_trunc('month', now())
                          , interval '1 month') m(study_month)
CROSS  JOIN rooms r
LEFT   JOIN (                                                  -- parentheses!
          studies s
   JOIN   teacher_contacts tc ON tc.id = s.teacher_contact_id  -- INNER JOIN!
   ) ON tc.teacher_id = t.id
    AND s.study_dt >= m.study_month
    AND s.study_dt <  m.study_month + interval '1 month'      -- sargable!
    AND s.room_id = r.id
GROUP  BY t.id, m.study_month, r.id  -- id is PK of respective tables
ORDER  BY t.id, m.study_month, r.id;

Poin utama

  • Buat kisi dari semua kombinasi yang diinginkan dengan CROSS JOIN . Dan kemudian LEFT JOIN ke baris yang ada. Terkait:

  • Dalam kasus Anda, ini adalah gabungan dari beberapa tabel, jadi saya menggunakan tanda kurung di FROM daftar ke LEFT JOIN ke hasil dari INNER JOIN dalam tanda kurung. Ini akan menjadi salah ke LEFT JOIN ke setiap tabel secara terpisah, karena Anda akan menyertakan klik pada kecocokan sebagian dan mendapatkan penghitungan yang berpotensi salah.

  • Dengan asumsi integritas referensial dan bekerja dengan kolom PK secara langsung, kita tidak perlu menyertakan rooms dan teachers di sisi kiri untuk kedua kalinya. Tapi kami masih memiliki gabungan dua tabel (studies dan teacher_contacts ). Peran teacher_contacts tidak jelas bagi saya. Biasanya, saya mengharapkan hubungan antara studies dan teachers secara langsung. Mungkin lebih disederhanakan ...

  • Kita perlu menghitung kolom non-null di sisi kiri untuk mendapatkan jumlah yang diinginkan. Sukai count(s.room_id)

  • Agar ini tetap cepat untuk tabel besar, pastikan predikat Anda sargable . Dan tambahkan indeks yang cocok .

  • Kolom teachers hampir (dapat diandalkan) unik. Beroperasi dengan ID unik, lebih disukai PK (lebih cepat dan lebih sederhana juga). Saya masih menggunakan teachers untuk output agar sesuai dengan hasil yang Anda inginkan. Sebaiknya sertakan ID unik, karena nama dapat digandakan.

  • Anda ingin:

    Jadi mulailah dengan date_trunc('month', now() - interval '12 month' (bukan 13). Itu sudah membulatkan awal dan melakukan apa yang Anda inginkan - lebih akurat daripada kueri awal Anda.

Karena Anda menyebutkan kinerja yang lambat, bergantung pada definisi tabel yang sebenarnya dan distribusi data, mungkin lebih cepat menggabungkan terlebih dahulu dan bergabung kemudian , seperti dalam jawaban terkait ini:

SELECT upper(trim(t.full_name)) AS teacher
     , m.mon                    AS study_month
     , r.room_code              AS room
     , COALESCE(s.ct, 0)        AS study_count

FROM   teachers t
CROSS  JOIN generate_series(date_trunc('month', now() - interval '12 month')  -- 12!
                          , date_trunc('month', now())
                          , interval '1 month') mon
CROSS  JOIN rooms r
LEFT   JOIN (                                                  -- parentheses!
   SELECT tc.teacher_id, date_trunc('month', s.study_dt) AS mon, s.room_id, count(*) AS ct
   FROM   studies s
   JOIN   teacher_contacts tc ON s.teacher_contact_id = tc.id
   WHERE  s.study_dt >= date_trunc('month', now() - interval '12 month')  -- sargable
   GROUP  BY 1, 2, 3
   ) s ON s.teacher_id = t.id
      AND s.mon = m.mon
      AND s.room_id = r.id
ORDER  BY 1, 2, 3;

Tentang kata penutup Anda:

Kemungkinan Anda bisa gunakan bentuk dua parameter crosstab() untuk menghasilkan hasil yang Anda inginkan secara langsung dan dengan kinerja yang sangat baik dan permintaan di atas tidak diperlukan untuk memulai. Pertimbangkan:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Bagaimana saya bisa memasukkan komentar kolom di PostgreSQL melalui Python?

  2. Pilih jumlah baris di tabel lain dalam pernyataan SELECT Postgres

  3. Bagaimana cara mendapatkan akhir hari?

  4. Regex untuk PostgreSQL untuk mendapatkan domain dengan sub-domain dari URL/Situs Web

  5. PostgreSQL 9.X representasi byte dalam 'hex' atau 'escape' untuk gambar mini