sql >> Database >  >> RDS >> PostgreSQL

De meest recente samengevoegde records per week samenvoegen

U hebt één gegevensitem per week en doel nodig (voordat u de tellingen per bedrijf aggregeert). Dat is een eenvoudige CROSS JOIN tussen generate_series() en goals . Het (mogelijk) dure deel is om de huidige state te krijgen van updates voor elk. Vind ik leuk @Paul heeft al voorgesteld , een LATERAL join lijkt de beste tool. Doe het alleen voor updates , en gebruik een snellere techniek met LIMIT 1 .

En vereenvoudig datumafhandeling met date_trunc() .

SELECT w_start
     , g.company_id
     , count(*) FILTER (WHERE u.status = 'green') AS green_count
     , count(*) FILTER (WHERE u.status = 'amber') AS amber_count
     , count(*) FILTER (WHERE u.status = 'red')   AS red_count
FROM   generate_series(date_trunc('week', NOW() - interval '2 months')
                     , date_trunc('week', NOW())
                     , interval '1 week') w_start
CROSS  JOIN goals g
LEFT   JOIN LATERAL (
   SELECT status
   FROM   updates
   WHERE  goal_id = g.id
   AND    created_at < w_start
   ORDER  BY created_at DESC
   LIMIT  1
   ) u ON true
GROUP  BY w_start, g.company_id
ORDER  BY w_start, g.company_id;

Om dit snel te maken je hebt een index met meerdere kolommen . nodig :

CREATE INDEX updates_special_idx ON updates (goal_id, created_at DESC, status);

Aflopende volgorde voor created_at is het beste, maar niet strikt noodzakelijk. Postgres kan indexen bijna net zo snel achteruit scannen. ( Niet van toepassing op omgekeerde sorteervolgorde van meerdere kolommen. )

Indexkolommen in dat bestellen. Waarom?

En de derde kolom state wordt alleen toegevoegd om snelle alleen-index scans toe te staan op updates . Verwant geval:

1k-doelen voor 9 weken (uw interval van 2 maanden overlapt met ten minste 9 weken) vereisen alleen 9k index-look-ups voor de 2e tabel van slechts 1k rijen. Voor kleine tabellen als deze zou de prestatie niet zo'n probleem moeten zijn. Maar zodra je er een paar duizend meer in elke tabel hebt, zullen de prestaties verslechteren bij opeenvolgende scans.

w_start staat voor het begin van elke week. De tellingen zijn dus voor het begin van de week. Je kunt haal nog steeds het jaar en de week uit (of andere details die uw week vertegenwoordigen), als u erop staat:

   EXTRACT(isoyear from w_start) AS year
 , EXTRACT(week    from w_start) AS week

Het beste met ISOYEAR , zoals @Paul heeft uitgelegd.

SQL Fiddle.

Gerelateerd:



  1. looping met een query en opzoektabel. mysql &php

  2. Moet ik !=of ​​<> gebruiken voor niet gelijk in T-SQL?

  3. Hoe een gegevenstabel invoegen in de SQL Server-databasetabel?

  4. Xmlparserv2-fout tijdens applicatie geïmplementeerd in jboss, Oracle ojdbc-module installeren in JBoss voor Java-webapplicatie