sql >> Database teknologi >  >> RDS >> PostgreSQL

Hvordan medtager man manglende data for flere grupperinger inden for tidsrummet?

Ud fra nogle antagelser (uklarheder i spørgsmålet) foreslår jeg:

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;

Vigtige punkter

  • Byg et gitter af alle ønskede kombinationer med CROSS JOIN . Og derefter LEFT JOIN til eksisterende rækker. Relateret:

  • I dit tilfælde er det en sammenføjning af flere tabeller, så jeg bruger parenteser i FROM liste til LEFT JOIN til resultatet af INNER JOIN inden for parentes. Det ville være forkert til LEFT JOIN til hver tabel separat, fordi du ville inkludere hits på delvise kampe og få potentielt forkerte optællinger.

  • Forudsat henvisningsintegritet og arbejder med PK-kolonner direkte, behøver vi ikke inkludere rooms og teachers på venstre side for anden gang. Men vi har stadig en sammenføjning af to tabeller (studies og teacher_contacts ). Rollen som teacher_contacts er uklart for mig. Normalt ville jeg forvente et forhold mellem studies og teachers direkte. Måske forenkles yderligere ...

  • Vi skal tælle en ikke-nul kolonne i venstre side for at få det ønskede antal. Ligesom count(s.room_id)

  • For at holde dette hurtigt for store borde skal du sørge for, at dine prædikater er sargable . Og tilføj matchende indekser .

  • Kolonnen teacher er næppe (pålideligt) unikt. Arbejd med et unikt ID, helst PK (også hurtigere og enklere). Jeg bruger stadig teacher for at outputtet matcher dit ønskede resultat. Det kan være klogt at inkludere et unikt ID, da navne kan være dubletter.

  • Du ønsker:

    Så start med date_trunc('month', now() - interval '12 month' (ikke 13). Det runder allerede starten ned og gør, hvad du vil - mere præcist end din oprindelige forespørgsel.

Da du nævnte langsom ydeevne, afhængigt af faktiske tabeldefinitioner og datadistribution, er det sandsynligvis hurtigere at samle først og slutte sig til senere , ligesom i dette relaterede svar:

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;

Om din afsluttende bemærkning:

Det er sandsynligt, at du kan brug to-parameter-formen crosstab() at producere dit ønskede resultat direkte og med fremragende ydeevne, og ovenstående forespørgsel er ikke nødvendig til at begynde med. Overvej:



  1. Hvordan mærker man grupper i postgresql, når gruppetilhørsforhold afhænger af den foregående linje?

  2. Brug af strace som et DG40DBC Debugging Tool på Linux

  3. Kan jeg automatisere indsættelse af adgangskode til PEM-fil til SSL-certifikater i MySQL?

  4. SQL-kommandoer snydeark – Sådan lærer du SQL på 10 minutter