PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

Làm thế nào để bao gồm dữ liệu bị thiếu cho nhiều nhóm trong khoảng thời gian?

Dựa trên một số giả định (sự không rõ ràng trong câu hỏi), tôi đề nghị:

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;

Những điểm chính

  • Xây dựng một lưới của tất cả các kết hợp mong muốn với CROSS JOIN . Và sau đó LEFT JOIN vào các hàng hiện có. Có liên quan:

  • Trong trường hợp của bạn, đó là sự kết hợp của một số bảng, vì vậy tôi sử dụng dấu ngoặc đơn trong FROM danh sách đến LEFT JOIN đến kết quả trong tổng số INNER JOIN trong ngoặc đơn. Nó sẽ không chính xác thành LEFT JOIN cho từng bảng riêng biệt, bởi vì bạn sẽ bao gồm các lần truy cập vào các trận đấu từng phần và nhận được số lượng có thể không chính xác.

  • Giả sử tính toàn vẹn của tham chiếu và làm việc trực tiếp với các cột PK, chúng tôi không cần bao gồm roomsteachers ở phía bên trái lần thứ hai. Nhưng chúng tôi vẫn có sự kết hợp của hai bảng (studiesteacher_contacts ). Vai trò của teacher_contacts không rõ ràng đối với tôi. Thông thường, tôi mong đợi mối quan hệ giữa các studiesteachers trực tiếp. Có thể được đơn giản hóa hơn nữa ...

  • Chúng ta cần đếm một cột không rỗng ở phía bên trái để có được số lượng mong muốn. Thích count(s.room_id)

  • Để duy trì tốc độ này cho các bảng lớn, hãy đảm bảo rằng các vị từ của bạn là sargable . Và thêm các chỉ mục phù hợp .

  • Cột teachers hầu như không (đáng tin cậy) là duy nhất. Hoạt động với một ID duy nhất, tốt nhất là PK (nhanh hơn và đơn giản hơn). Tôi vẫn đang sử dụng teacher để đầu ra phù hợp với kết quả mong muốn của bạn. Có thể là khôn ngoan nếu bao gồm một ID duy nhất, vì tên có thể trùng lặp.

  • Bạn muốn:

    Vì vậy, hãy bắt đầu với date_trunc('month', now() - interval '12 month' (không phải 13). Điều đó làm tròn phần bắt đầu đã có và thực hiện những gì bạn muốn - chính xác hơn truy vấn ban đầu của bạn.

Vì bạn đã đề cập đến hiệu suất chậm, tùy thuộc vào định nghĩa bảng thực tế và phân phối dữ liệu, việc tổng hợp trước và tham gia sau có thể nhanh hơn , như trong câu trả lời có liên quan này:

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;

Về nhận xét kết thúc của bạn:

Rất có thể bạn có thể sử dụng dạng hai tham số của crosstab() để tạo ra kết quả mong muốn của bạn một cách trực tiếp và với hiệu suất tuyệt vời và không cần bắt đầu truy vấn trên. Cân nhắc:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Pl / pgSQL không có tham số $ 1 trong câu lệnh EXECUTE

  2. Làm thế nào để đọc tất cả các hàng từ bảng lớn?

  3. Cách lặp qua Mảng JSON trong postgresql 9.3

  4. Làm việc với ngày tháng trong PostgreSQL

  5. lỗi:truy vấn con chỉ được trả về một cột