sql >> Databáze >  >> RDS >> PostgreSQL

Agregace posledních připojených záznamů za týden

Potřebujete jednu datovou položku na týden a cíl (před agregací počtů na společnost). To je prostý CROSS JOIN mezi generate_series() a goals . (Možná) nákladná část je získat aktuální state z updates pro každého. Líbí se mi @Paul již navrhl , LATERAL join se zdá jako nejlepší nástroj. Udělejte to pouze pro updates a použijte rychlejší techniku ​​s LIMIT 1 .

A zjednodušit zpracování dat pomocí 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;

Aby to bylo rychlé potřebujete vícesloupcový index :

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

Sestupné pořadí pro created_at je nejlepší, ale není nezbytně nutný. Postgres dokáže skenovat indexy pozpátku téměř stejně rychle. ( Nelze však použít pro obrácené pořadí řazení více sloupců. )

Indexujte sloupce v tom objednat. Proč?

A třetí sloupec state je připojen pouze proto, aby umožňoval rychlé prohledávání pouze na základě indexu na updates . Související případ:

1 000 cílů za 9 týdnů (váš interval 2 měsíců se překrývá s alespoň 9 týdny) vyžaduje pouze 9 000 vyhledání indexu pro 2. tabulku pouze o 1 000 řádcích. U malých stolů, jako je tento, by výkon neměl být velkým problémem. Ale jakmile budete mít v každé tabulce o pár tisíc více, výkon se bude sekvenčním skenováním zhoršovat.

w_start představuje začátek každého týdne. V důsledku toho jsou počty pro začátek týdne. můžete stále extrahujte rok a týden (nebo jakékoli jiné podrobnosti představující váš týden), pokud na tom trváte:

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

Nejlepší s ISOYEAR , jak vysvětlil @Paul.

SQL Fiddle.

Související:



  1. MySQL – NEJSOU pro primární klíče potřeba omezení NULL?

  2. Předejte číslo jako název sloupce ve vybraném příkazu SQL

  3. Mac + virtualenv + pip + postgresql =Chyba:Spustitelný soubor pg_config nebyl nalezen

  4. Nelze najít sloupec dbo nebo uživatelem definovanou funkci nebo agregaci dbo.Splitfn nebo je název nejednoznačný