sql >> Database >  >> RDS >> PostgreSQL

Hoe ontbrekende gegevens voor meerdere groeperingen binnen de tijdspanne op te nemen?

Op basis van enkele aannames (ambiguïteiten in de vraag) stel ik voor:

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;

Belangrijkste punten

  • Bouw een raster van alle gewenste combinaties met CROSS JOIN . En dan LEFT JOIN naar bestaande rijen. Gerelateerd:

  • In jouw geval is het een samenvoeging van meerdere tabellen, dus ik gebruik haakjes in de FROM lijst naar LEFT JOIN naar het resultaat van INNER JOIN tussen haakjes. Het zou onjuist zijn naar LEFT JOIN naar elke tafel afzonderlijk, omdat je dan treffers op gedeeltelijke overeenkomsten zou opnemen en mogelijk onjuiste tellingen zou krijgen.

  • Uitgaande van referentiële integriteit en als we rechtstreeks met PK-kolommen werken, hoeven we geen rooms op te nemen en teachers een tweede keer aan de linkerkant. Maar we hebben nog steeds een combinatie van twee tabellen (studies en teacher_contacts ). De rol van teacher_contacts is mij onduidelijk. Normaal gesproken zou ik een verband verwachten tussen studies en teachers direct. Kan verder worden vereenvoudigd ...

  • We moeten een niet-null-kolom aan de linkerkant tellen om de gewenste tellingen te krijgen. Like count(s.room_id)

  • Om dit snel te houden voor grote tafels, moet u ervoor zorgen dat uw predikaten sargable zijn . En voeg bijpassende indexen toe .

  • De kolom teacher is nauwelijks (betrouwbaar) uniek. Werk met een unieke ID, bij voorkeur de PK (sneller en eenvoudiger ook). Ik gebruik nog steeds teacher zodat de uitvoer overeenkomt met uw gewenste resultaat. Het kan verstandig zijn om een ​​unieke ID op te nemen, aangezien namen dubbel kunnen zijn.

  • Je wilt:

    Dus begin met date_trunc('month', now() - interval '12 month' (niet 13). Dat is al een afronding naar beneden en doet wat u wilt - nauwkeuriger dan uw oorspronkelijke zoekopdracht.

Aangezien u trage prestaties noemde, afhankelijk van de werkelijke tabeldefinities en gegevensdistributie, is het waarschijnlijk sneller om eerst samen te voegen en later deel te nemen , zoals in dit gerelateerde antwoord:

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;

Over je slotopmerking:

De kans is groot dat je kunt gebruik de twee-parametervorm van crosstab() om uw gewenste resultaat direct en met uitstekende prestaties te produceren en de bovenstaande vraag is om te beginnen niet nodig. Overweeg:



  1. Hoe om te gaan met meerdere joins

  2. JQuery, slepen en neerzetten en opslaan in mysql-database?

  3. Transactie afhandelen in multithreaded omgeving

  4. Zijn kolom- en tabelnaam hoofdlettergevoelig in MySQL?