カウントすべて 行
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 ..-1
。 -
ウィンドウ関数のデフォルトフレーム
ORDER BY
を使用OVER
で 句の使用は、UNBOUNDEDPRECEDINGとCURRENTROWの間の範囲
です。 。それがまさにあなたが必要としているものです。 -
UNION ALL
を使用する 、UNION
ではありません 。 -
time_series
の不幸な選択 (D、W、M)はうまくソートされないので、名前を変更して、最終的なORDER BY
にしました。 簡単です。 -
このクエリは、1日に複数の行を処理できます。カウントには、1日のすべてのピアが含まれます。
-
DISTINCT ON
の詳細 :
1日あたりのDISTINCTユーザー
すべてのユーザーを1日に1回だけカウントするには、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
動的な期間にわたるDISTINCTユーザー
いつでも相関サブクエリに頼ることができます 。大きなテーブルでは遅くなる傾向があります!
前のクエリに基づいて構築する:
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フィドル 3つのソリューションすべてに対して。
density_rank()
で高速化
@Clodoaldo
大きな改善を思いついた:ウィンドウ関数dense_rankを使用する()
。最適化されたバージョンの別のアイデアがあります。毎日の重複をすぐに除外する方がさらに速いはずです。パフォーマンスの向上は、1日あたりの行数とともに増加します。
簡略化およびサニタイズされたデータモデルに基づいて構築する -冗長な列なし-day
date
の代わりに列名として
日付コード> は
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フィドル
4つのより高速なバリアントのパフォーマンスを示しています。それはあなたにとって最速のデータ分布に依存します。
それらはすべて、相関サブクエリバージョンの約10倍の速度です(相関サブクエリにとっては悪くありません)。