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

Изберете отделна потребителска група по период от време

Преброяване на всички редове

SELECT date, '1_D' AS time_series,  count(DISTINCT user_id) AS cnt
FROM   uniques
GROUP  BY 1

UNION  ALL
SELECT DISTINCT ON (1)
       date, '2_W', count(*) OVER (PARTITION BY week_beg ORDER BY date)
FROM   uniques

UNION  ALL
SELECT DISTINCT ON (1)
       date, '3_M', count(*) OVER (PARTITION BY month_beg ORDER BY date)
FROM   uniques
ORDER  BY 1, time_series
  • Вашите колони week_beg и month_beg са 100 % излишни и могат лесно да бъдат заменени сdate_trunc('week', date + 1) - 1 и date_trunc('month', date) съответно.

  • Седмицата ви изглежда започва в неделя (отстъпка с едно), следователно + 1 .. - 1 .

  • кадър по подразбиране на функция за прозорец с ORDER BY в OVER използваната клауза е RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW . Точно това ви трябва.

  • Използвайте UNION ALL , а не UNION .

  • Вашият неудачен избор за time_series (D, W, M) не сортира добре, преименувах, за да направя крайния ORDER BY по-лесно.

  • Тази заявка може да обработва няколко реда на ден. Преброяването включва всички връстници за един ден.

  • Повече за DISTINCT ON :

ОТДЕЛНИ потребители на ден

За да броите всеки потребител само веднъж на ден, използвайте CTE с DISTINCT ON :

WITH x AS (SELECT DISTINCT ON (1,2) date, user_id FROM uniques)
SELECT date, '1_D' AS time_series,  count(user_id) AS cnt
FROM   x
GROUP  BY 1

UNION ALL
SELECT DISTINCT ON (1)
       date, '2_W'
      ,count(*) OVER (PARTITION BY (date_trunc('week', date + 1)::date - 1)
                      ORDER BY date)
FROM   x

UNION ALL
SELECT DISTINCT ON (1)
       date, '3_M'
      ,count(*) OVER (PARTITION BY date_trunc('month', date) ORDER BY date)
FROM   x
ORDER BY 1, 2

ОТДЕЛНИ потребители за динамичен период от време

Винаги можете да прибегнете до свързани подзаявки . Склонни да бъдат бавни с големи маси!
Надграждане на предишните заявки:

WITH du AS (SELECT date, user_id FROM uniques GROUP BY 1,2)
    ,d  AS (
    SELECT date
          ,(date_trunc('week', date + 1)::date - 1) AS week_beg
          ,date_trunc('month', date)::date AS month_beg
    FROM   uniques
    GROUP  BY 1
    )
SELECT date, '1_D' AS time_series,  count(user_id) AS cnt
FROM   du
GROUP  BY 1

UNION ALL
SELECT date, '2_W', (SELECT count(DISTINCT user_id) FROM du
                     WHERE  du.date BETWEEN d.week_beg AND d.date )
FROM   d
GROUP  BY date, week_beg

UNION ALL
SELECT date, '3_M', (SELECT count(DISTINCT user_id) FROM du
                     WHERE  du.date BETWEEN d.month_beg AND d.date)
FROM   d
GROUP  BY date, month_beg
ORDER  BY 1,2;

SQL Fiddle и за трите решения.

По-бързо с dense_rank()

@Clodoaldo излезе със значително подобрение:използвайте прозоречната функция dense_rank() . Ето още една идея за оптимизирана версия. Трябва да е още по-бързо, за да изключите ежедневните дубликати веднага. Увеличаването на производителността нараства с броя на редовете на ден.

Надграждане на опростен и дезинфекциран модел на данни - без излишните колони - day като име на колона вместо date

date е запазена дума в стандартен SQL и име на основен тип в PostgreSQL и не трябва да се използва като идентификатор.

CREATE TABLE uniques(
   day date     -- instead of "date"
  ,user_id int
);

Подобрена заявка:

WITH du AS (
   SELECT DISTINCT ON (1, 2)
          day, user_id 
         ,date_trunc('week',  day + 1)::date - 1 AS week_beg
         ,date_trunc('month', day)::date         AS month_beg
   FROM   uniques
   )
SELECT day, count(user_id) AS d, max(w) AS w, max(m) AS m
FROM  (
    SELECT user_id, day
          ,dense_rank() OVER(PARTITION BY week_beg  ORDER BY user_id) AS w
          ,dense_rank() OVER(PARTITION BY month_beg ORDER BY user_id) AS m
    FROM   du
    ) s
GROUP  BY day
ORDER  BY day;

SQL Fiddle демонстрирайки производителността на 4 по-бързи варианта. Зависи от вашето разпространение на данни кое е най-бързо за вас.
Всички те са около 10 пъти по-бързи от версията на корелирани подзаявки (което не е лошо за корелирани подзаявки).



  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. postgres не разпознава временна таблица във функция

  3. Какъв е типът Дата в npgsql?

  4. Restful Api експресна база данни на postgres

  5. PostgreSQL множество транзакции на една и съща връзка