PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Обединяване на най-новите присъединени записи на седмица

Имате нужда от един елемент от данни на седмица и цел (преди обобщаване на броя за компания). Това е обикновен CROSS JOIN между generate_series() и goals . (Възможно) скъпата част е да получите текущото state от updates за всеки. Като @Paul вече е предложен , LATERAL join изглежда като най-добрият инструмент. Правете го само за updates , но използвайте по-бърза техника с LIMIT 1 .

И опростете обработката на дати с 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;

За да направите товабързо имате нужда от многоколонен индекс :

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

Низходящ ред за created_at е най-добре, но не е строго необходимо. Postgres може да сканира индекси назад почти точно толкова бързо. ( Но не е приложимо за обърнат ред на сортиране на множество колони. )

Индексирайте колони в това поръчка. Защо?

И третата колона status се добавя само за да позволи бързо сканиране само за индекс на updates . Свързан случай:

1k цели за 9 седмици (вашият интервал от 2 месеца се припокрива с поне 9 седмици) изискват само 9k индексни справки за втората таблица от само 1k реда. За малки маси като тази производителността не би трябвало да е голям проблем. Но след като имате няколко хиляди повече във всяка таблица, производителността ще се влоши при последователни сканирания.

w_start представлява началото на всяка седмица. Следователно преброяването е за началото на седмицата. Вие можете все още извличайте година и седмица (или всякакви други подробности, представляващи вашата седмица), ако настоявате:

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

Най-добро с ISOYEAR , както @Paul обясни.

SQL Fiddle.

Свързани:



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Неуспешна връзка с AWS RDS Postgres

  2. ST_DWithin приема параметър като градус, а не метри, защо?

  3. Как да стартирате работа, създадена чрез pgagent в Postgres

  4. Mac OSX Lion Postgres не приема връзки на /tmp/.s.PGSQL.5432

  5. Получаването не може да се ангажира, когато е активирано автоматично изключение при работа с CachedRowSet в JDBC