2017-09-13 38 views
5

aşağıdaki tablo vardır:Bir tarih aralığı nasıl oluşturulur + PostgreSQL'de başka bir tablodan önceki tarihleri ​​nasıl sayılır?

links:

created_at   active 
2017-08-12 15:46:01 false 
2017-08-13 15:46:01 true 
2017-08-14 15:46:01 true 
2017-08-15 15:46:01 false 

bir tarih aralığı verilir, ben birçok etken bağlantılar bir tarihe eşit veya geçerli daha küçük üzerinde nasıl yaratıldığını söyler zaman serilerini ayıklamak zorunda (haddeleme) tarihi.

Çıkış (tarih aralığı 2017/08/12 için - 2017/08/17):

SELECT date_trunc('day', dd):: date 
FROM generate_series 
    ('2017-08-12'::timestamp 
    , '2017-08-17'::timestamp 
    , '1 day'::interval) dd 

Ama haddeleme:

day   count 
2017-08-12 0 (there are 0 active links created on 2017-08-12 and earlier) 
2017-08-13 1 (there is 1 active link created on 2017-08-13 and earlier) 
2017-08-14 2 (there are 2 active links created on 2017-08-14 and earlier) 
2017-08-15 2 ... 
2017-08-16 2 
2017-08-17 2 

Ben üreten tarihlerde aşağıdaki sorgu ile geldi sayım beni şaşırtıyor ve nasıl devam edeceğime emin değilim. Bu bir pencere fonksiyonu ile çözülebilir mi? -

cevap

1

Bu hızlı olmalıdır:

SELECT day::date 
    , sum(ct) OVER (ORDER BY day) AS count 
FROM generate_series (timestamp '2017-08-12' 
         , timestamp '2017-08-17' 
         , interval '1 day') day 
LEFT JOIN (
    SELECT date_trunc('day', created_at) AS day, count(*) AS ct 
    FROM tbl 
    WHERE active -- fastest 
    GROUP BY 1 
    ) t USING (day) 
ORDER BY 1; 

dbfiddle Eğer count(active OR NULL) kullanabilir böylece here

count() sadece boş olmayan satırları sayar. Ancak, sayım için en hızlı seçenek, ilgisiz satırları başlamak üzere WHERE yan tümcesiyle hariç tutmaktır. Bütün günlerini generate_series() ile eklediğimizden beri, bu en iyi seçenek.

karşılaştırın: Ben (çok biraz daha hızlı) eşleşen damgaları almak için date_trunc() kullanmak

(değil date) timestamp döner generate_series() beri.

1

Sadece toplanmasına ve kümülatif toplamları kullanmak sizi varsayarak günde en az birine sahip:

select date_trunc('day', created_at)::date as created_date, 
     sum(active::int) as actives, 
     sum(sum(active::int)) over (date_trunc('day', created_at)) as running_actives 
from t 
group by created_date; 

veri delik varsa sadece tarih oluşturmak gerekir. Eğer yaparsanız, where active'u dahil etmenizi tavsiye ederim - şimdi ekleyebilirsiniz, sadece delik olmadığından emin olmak istiyorum.

+0

Evet, delikler var, bazı günler kayıp. Öyleyse, o günler için var olan en son tarihin sayımını yapmak zorundayım. –

0

Böyle bir sorgu size yardımcı olabilir düşünüyorum: Eğer tablodaki eksik gün varsa() bunları oluşturmak için

;with t as (SELECT date_trunc('day', dd):: date 
FROM generate_series 
    ('2017-08-12'::timestamp 
    , '2017-08-17'::timestamp 
    , '1 day'::interval) dd 
) 
select distinct t.date_trunc 
    , count(case when links.active = 'true' then 1 end) over (order by links.created_at) count 
from t 
left join links 
on t.date_trunc = cast(links.created_at as date) 
order by t.date_trunc; 

SQL Fiddle Demo

0

, bir generate_series kullanmanız gerekir . Bu temelde önceki iki cevabı bir araya getirdiğinden, kredi verilir ;;)

Bununla birlikte, bu katılım daha önce değil, yalnızca günde bir satır döndüren GROUP BY'den sonra daha iyi yapılır. daha büyük bir JOIN.

WITH dailydata AS (
    SELECT 
    d::DATE, COALESCE(n,0) n 
    FROM 
    generate_series( 
     '2000-01-01'::DATE, 
     '2000-10-01'::DATE, 
     '1 DAY'::INTERVAL) d 
    LEFT JOIN 
    (SELECT created_at::DATE d, count(*) AS n 
    FROM links WHERE active 
    GROUP BY d) data 
    USING (d) 
) 
SELECT d, n, sum(n) OVER (ORDER BY d) FROM dailydata; 
0
CREATE TABLE links 
     (created_at   timestamp 
     , active boolean 
     ); 
INSERT INTO links(created_at,active)VALUES 
('2017-08-12 15:46:01', false) 
,('2017-08-13 15:46:01', true) 
,('2017-08-14 15:46:01', true) 
,('2017-08-15 15:46:01', false) 
     ; 

WITH cal AS (
     select gs AS deet 
     FROM generate_series('2017-08-11'::date,'2017-08-16'::date, '1day'::interval)gs 
     ) 
SELECT cal.deet 
     , SUM(1) FILTER (WHERE l.active =True) OVER(ORDER BY l.created_at) AS cumsum 
FROM cal 
LEFT JOIN links l ON date_trunc('days', l.created_at)= cal.deet 
ORDER BY created_at 
     ; 
1

Demo

http://rextester.com/OGZV44492

SQL

SELECT date_trunc('day', dd):: date AS day, 
     (SELECT COUNT(*) FROM links 
     WHERE active = true 
      AND date(created_at) <= date_trunc('day', dd)) AS "count" 
FROM generate_series 
    ('2017-08-12'::timestamp 
    , '2017-08-17'::timestamp 
    , '1 day'::interval) dd 

açıklama

SQL yukarıda olan tarih bölümü oluşturulan aralığında daha az ya da, günümüze kadar eşit links tablodaki satır sayısını saymak için basit Alt Seç'i yapar.

+1

Gerçekten bunu seviyorum! Teşekkürler Steve. –

+0

Bu sorgunun çok büyük bir tablo için iyi ölçeklenmediğini fark ettim, bu yüzden Erwin'in cevabını seçtim. –

İlgili konular