2017-09-13 15 views
5

मैं निम्न तालिका है:दिनांक सीमा कैसे उत्पन्न करें + PostgreSQL में किसी अन्य तालिका से पहले की तारीखों की गणना करें?

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 

जब एक तिथि सीमा को देखते हुए, मैं समय श्रृंखला जो मुझसे कहता है कि कितने सक्रिय लिंक एक तिथि के बराबर या वर्तमान की तुलना में छोटे पर बनाए गए निकालने के लिए है (रोलिंग) तिथि।

आउटपुट (तिथि सीमा 2017/08/12 के लिए - 2017/08/17):

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

लेकिन रोलिंग:

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 

मैं पैदा दिनांकों निम्न क्वेरी के साथ आया था मायने रखता है मुझे भ्रमित करता है और मुझे यकीन है कि कैसे जारी रखना है। क्या इसे विंडो फ़ंक्शन के साथ हल किया जा सकता है? -

उत्तर

1

यह सबसे तेजी से किया जाना चाहिए:

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 here

count() केवल गैर-शून्य पंक्तियों में गिना जाता है, तो आप count(active OR NULL) इस्तेमाल कर सकते हैं। लेकिन गिनने के लिए सबसे तेज़ विकल्प है WHERE खंड के साथ अप्रासंगिक पंक्तियों को बाहर करना है। चूंकि हम generate_series() के साथ सभी दिन जोड़ रहे हैं, यह सबसे अच्छा विकल्प है।

की तुलना करें:

generate_series() के बाद रिटर्न timestamp (नहीं date) मैं date_trunc() का उपयोग मिलान timestamps (बहुत थोड़ा तेज) प्राप्त करने के लिए।

1

मैं सिर्फ एकत्रीकरण और संचयी रकम का प्रयोग करेंगे आप यह सोचते हैं प्रति दिन कम से कम एक है:

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; 

यदि आप डेटा में छेद है आप केवल दिनांकों उत्पन्न करने के लिए की जरूरत है। यदि आप करते हैं, तो मैं where active सहित अनुशंसा करता हूं - अब आप इसे शामिल कर सकते हैं, मैं बस यह सुनिश्चित करना चाहता हूं कि कोई छेद नहीं है।

+0

हां, छेद हैं, कुछ दिन गुम हैं। तो उन दिनों के लिए मुझे सबसे हाल की पिछली तारीख के लिए गिनती लेनी होगी। –

0

मुझे लगता है कि इस तरह एक प्रश्न आप मदद कर सकते हैं:

;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

आप अपनी तालिका में लापता दिन है, तो आप() उन्हें बनाने के लिए एक generate_series का उपयोग करना होगा । चूंकि यह मूल रूप से दो पिछले उत्तरों को एक साथ रख रहा है, क्रेडिट दिया जाता है;;

हालांकि, यह शामिल ग्रुप बी के बाद बेहतर होता है, जो प्रति दिन केवल एक पंक्ति लौटाएगा, जिसके परिणामस्वरूप, एक बड़ी जॉइन

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

डेमो

http://rextester.com/OGZV44492

एसक्यूएल

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 

स्पष्टीकरण

एसक्यूएल ऊपर links तालिका जिसका तारीख हिस्सा उत्पन्न रेंज में से कम या उसके प्रत्येक तिथि के बराबर है में पंक्तियों की संख्या गिनती करने के लिए एक सरल सबसिलेक्ट करता है।

+1

मुझे यह वाकई पसंद है! धन्यवाद स्टीव। –

+0

मुझे एहसास हुआ कि यह क्वेरी बहुत बड़ी तालिका के लिए अच्छी तरह से स्केल नहीं करती है, इसलिए मैंने इरविन के जवाब का चयन किया। –

संबंधित मुद्दे

 संबंधित मुद्दे