count
とgroup by
を使用して、毎日登録されているサブスクライバーの数を取得しています。
SELECT created_at, COUNT(email)
FROM subscriptions
GROUP BY created at;
結果:
created_at count
-----------------
04-04-2011 100
05-04-2011 50
06-04-2011 50
07-04-2011 300
代わりに、毎日加入者の累積合計を取得します。どうすれば入手できますか?
created_at count
-----------------
04-04-2011 100
05-04-2011 150
06-04-2011 200
07-04-2011 500
より大きなデータセットでは、 window functions がこれらの種類のクエリを実行する最も効率的な方法です-テーブルのみがスキャンされます自己結合のように、日付ごとに1回ではなく、1回。また、はるかにシンプルに見えます。 :) PostgreSQL 8.4以降では、ウィンドウ関数がサポートされています。
これは次のようになります。
_SELECT created_at, sum(count(email)) OVER (ORDER BY created_at)
FROM subscriptions
GROUP BY created_at;
_
ここで、OVER
はウィンドウを作成します。 _ORDER BY created_at
_は、カウントを_created_at
_の順序で合計する必要があることを意味します。
編集:1日以内に重複するメールを削除する場合は、sum(count(distinct email))
を使用できます。残念ながら、これは異なる日付にまたがる重複を削除しません。
all重複を削除したい場合、サブクエリと_DISTINCT ON
_を使用するのが最も簡単だと思います。これにより、電子メールは最も早い日付に関連付けられます(created_atで昇順に並べ替えているため、最も早い日付が選択されます)。
_SELECT created_at, sum(count(email)) OVER (ORDER BY created_at)
FROM (
SELECT DISTINCT ON (email) created_at, email
FROM subscriptions ORDER BY email, created_at
) AS subq
GROUP BY created_at;
_
_(email, created_at)
_にインデックスを作成する場合、このクエリも遅くなりません。
(テストする場合、これがサンプルデータセットの作成方法です)
_create table subscriptions as
select date '2000-04-04' + (i/10000)::int as created_at,
'[email protected]' || (i%700000)::text as email
from generate_series(1,1000000) i;
create index on subscriptions (email, created_at);
_
つかいます:
SELECT a.created_at,
(SELECT COUNT(b.email)
FROM SUBSCRIPTIONS b
WHERE b.created_at <= a.created_at) AS count
FROM SUBSCRIPTIONS a
SELECT
s1.created_at,
COUNT(s2.email) AS cumul_count
FROM subscriptions s1
INNER JOIN subscriptions s2 ON s1.created_at >= s2.created_at
GROUP BY s1.created_at
私はあなたが1日に1行だけが必要であり、サブスクリプションなしでまだ日を表示したいと仮定します(特定の日付に誰もサブスクライブしていないと仮定すると、前日の残高でその日付を表示しますか?)この場合、「with」機能を使用できます。
with recursive serialdates(adate) as (
select cast('2011-04-04' as date)
union all
select adate + 1 from serialdates where adate < cast('2011-04-07' as date)
)
select D.adate,
(
select count(distinct email)
from subscriptions
where created_at between date_trunc('month', D.adate) and D.adate
)
from serialdates D