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

Заявка за брой различни стойности в подвижния период от време

Тестов случай:

CREATE TABLE tbl (date date, email text);
INSERT INTO tbl VALUES
  ('2012-01-01', '[email protected]')
, ('2012-01-01', '[email protected]')
, ('2012-01-01', '[email protected]')
, ('2012-01-02', '[email protected]')
, ('2012-01-02', '[email protected]')
, ('2012-01-03', '[email protected]')
, ('2012-01-04', '[email protected]')
, ('2012-01-05', '[email protected]')
, ('2012-01-05', '[email protected]')
, ('2012-01-06', '[email protected]')
, ('2012-01-06', '[email protected]')
, ('2012-01-06', '[email protected]`')
;

Заявка - връща само дни, в които съществува запис в tbl :

SELECT date
     ,(SELECT count(DISTINCT email)
       FROM   tbl
       WHERE  date BETWEEN t.date - 2 AND t.date -- period of 3 days
      ) AS dist_emails
FROM   tbl t
WHERE  date BETWEEN '2012-01-01' AND '2012-01-06'  
GROUP  BY 1
ORDER  BY 1;

Или - върнете всички дни в посочения диапазон, дори ако няма редове за деня:

SELECT date
     ,(SELECT count(DISTINCT email)
       FROM   tbl
       WHERE  date BETWEEN g.date - 2 AND g.date
      ) AS dist_emails
FROM  (SELECT generate_series(timestamp '2012-01-01'
                            , timestamp '2012-01-06'
                            , interval  '1 day')::date) AS g(date);

db<>цигулка тук

Резултат:

day        | dist_emails
-----------+------------
2012-01-01 | 3
2012-01-02 | 3
2012-01-03 | 3
2012-01-04 | 3
2012-01-05 | 1
2012-01-06 | 2

Това звучеше като работа за функции на прозореца в началото, но не намерих начин да дефинирам подходящата рамка на прозореца. Също така, според документация:

Функциите на прозореца за обобщени, за разлика от нормалните агрегатни функции, не позволяват DISTINCT или ORDER BY да се използва в списъка с аргументи на функцията.

Затова го реших с корелирани подзаявки вместо това. Предполагам, че това е най-умният начин.

Между другото, "между посочената дата и преди 3 дни" ще бъде период от 4 дни. Определението ти е противоречиво.

Малко по-кратко, но по-бавно за няколко дни:

SELECT g.date, count(DISTINCT email) AS dist_emails
FROM  (SELECT generate_series(timestamp '2012-01-01'
                            , timestamp '2012-01-06'
                            , interval  '1 day')::date) AS g(date)
LEFT   JOIN tbl t ON t.date BETWEEN g.date - 2 AND g.date
GROUP  BY 1
ORDER  BY 1;

Свързано:

  • Генериране на времеви серии между две дати в PostgreSQL
  • Подвижен брой редове във времевия интервал


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL:сериен срещу самоличност

  2. Големите обекти не могат да се използват в режим на автоматично записване

  3. Върнете нула, ако не бъде намерен запис

  4. SQL:Изберете записи, където ВСИЧКИ съединени записи отговарят на някакво условие

  5. как мога да създам нов XML файл от съществуваща база данни в PostgreSQL база данни с помощта на java