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

Vyberte odlišnou skupinu uživatelů podle časového období

Počítat vše řádky

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
  • Vaše sloupce week_beg a month_beg jsou 100 % nadbytečné a lze je snadno nahradit date_trunc('week', date + 1) - 1 a date_trunc('month', date) respektive.

  • Zdá se, že váš týden začíná v neděli (o jedničku), proto + 1 .. - 1 .

  • výchozí rámec funkce okna pomocí ORDER BY v OVER klauzule používá je RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW . To je přesně to, co potřebujete.

  • Použijte UNION ALL , nikoli UNION .

  • Vaše nešťastná volba pro time_series (D, W, M) netřídí dobře, přejmenoval jsem, aby bylo konečné ORDER BY jednodušší.

  • Tento dotaz může pracovat s více řádky za den. Počty zahrnují všechny partnery za den.

  • Další informace o DISTINCT ON :

DISTINCT uživatelů za den

Chcete-li započítat každého uživatele pouze jednou denně, použijte CTE s 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

DISTINCT uživatelů za dynamické časové období

Vždy se můžete uchýlit ke korelovaným dílčím dotazům . U velkých stolů bývá pomalý!
Navazuje na předchozí dotazy:

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 pro všechna tři řešení.

Rychlejší pomocí dense_rank()

@Clodoaldo přišel s velkým vylepšením:použijte funkci okna dense_rank() . Zde je další nápad na optimalizovanou verzi. Okamžité vyloučení denních duplikátů by mělo být ještě rychlejší. Nárůst výkonu roste s počtem řádků za den.

Na základě zjednodušeného a čistého datového modelu - bez nadbytečných sloupců- day jako název sloupce namísto date

date je rezervované slovo ve standardním SQL a základní název typu v PostgreSQL a neměl by být používán jako identifikátor.

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

Vylepšený dotaz:

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 demonstrující výkon 4 rychlejších variant. Záleží na vaší distribuci dat, která je pro vás nejrychlejší.
Všechny jsou asi 10x rychlejší než verze s korelovanými poddotazy (což u korelovaných poddotazů není špatné).



  1. Upgradovat WAMP na MySQL 5.5?

  2. Výsledky Mysql v PHP - pole nebo objekty?

  3. nekonzistentní odsazení s Pythonem po rozdělení

  4. Tabulka SQL Server Temp vs proměnná tabulky