DB डिज़ाइन
जबकि आप कर सकते हैं अलग से काम करें तारीख
और समय
कॉलम, वास्तव में एकल timestamp<पर कोई लाभ नहीं है /कोड>
कॉलम। मैं अनुकूलित करूंगा:
ALTER TABLE tbl ADD column ts timestamp;
UPDATE tbl SET ts = date + time; -- assuming actual date and time types
ALTER TABLE tbl DROP column date, DROP column time;
यदि दिनांक और समय वास्तविक नहीं हैं तारीख
और समय
डेटा प्रकार, उपयोग करें to_timestamp()
. संबंधित:
क्वेरी
फिर क्वेरी थोड़ी आसान हो जाती है:
SELECT *
FROM (
SELECT sn, generate_series(min(ts), max(ts), interval '5 min') AS ts
FROM tbl
WHERE sn = '4as11111111'
AND ts >= '2018-01-01'
AND ts < '2018-01-02'
GROUP BY 1
) grid
CROSS JOIN LATERAL (
SELECT round(avg(vin1), 2) AS vin1_av
, round(avg(vin2), 2) AS vin2_av
, round(avg(vin3), 2) AS vin3_av
FROM tbl
WHERE sn = grid.sn
AND ts >= grid.ts
AND ts < grid.ts + interval '5 min'
) avg;
db<>fiddle यहां
पहली सबक्वेरी ग्रिड
. में प्रारंभ समय का ग्रिड जेनरेट करें , प्रथम से अंतिम योग्यता . तक चल रहा है दी गई समय सीमा में पंक्ति।
प्रत्येक पार्टीशन में आने वाली पंक्तियों में LATERAL
. के साथ शामिल हों सबक्वेरी औसत
. में शामिल हों और तुरंत औसत एकत्र करें . समुच्चय के कारण, यह हमेशा कोई प्रविष्टि नहीं मिलने पर भी एक पंक्ति लौटाता है। औसत डिफ़ॉल्ट NULL
. है इस मामले में।
परिणाम में दी गई समय सीमा में पहली और अंतिम क्वालीफाइंग पंक्ति के बीच सभी समय स्लॉट शामिल हैं। विभिन्न अन्य परिणाम रचनाएँ भी समझ में आएंगी। जैसे सभी को शामिल करना दी गई समय सीमा में समय स्लॉट या वास्तविक मूल्यों के साथ केवल समय स्लॉट। हर संभव, मुझे एक व्याख्या चुननी पड़ी।
सूचकांक
कम से कम यह बहु-स्तंभ अनुक्रमणिका रखें:
CRATE INDEX foo_idx ON tbl (sn, ts);
या (sn, ts, vin1, vin2, vin3)
. पर केवल अनुक्रमणिका स्कैन की अनुमति देने के लिए - यदि कुछ पूर्व शर्त पूरी होती हैं और विशेष रूप से यदि तालिका पंक्तियाँ डेमो की तुलना में बहुत व्यापक हैं।
निकट से संबंधित:
- समय अंतराल के साथ सीटीई पर धीरे-धीरे बाएं शामिल हों
- Rails+Postgres में मनमाने समय अंतराल द्वारा रिकॉर्ड गिनने का सबसे अच्छा तरीका
आपकी मूल तालिका के आधार पर
जैसा अनुरोध किया गया है और टिप्पणी में स्पष्ट किया गया है
, और बाद में कॉलम mac
. को शामिल करने के लिए प्रश्न में फिर से अपडेट किया गया और स्थान
. मुझे लगता है कि आप प्रति (mac, loc)
. के लिए अलग औसत चाहते हैं ।
तारीख
और समय
अभी भी अलग कॉलम हैं, vin* कॉलम टाइप हैं float
, और पंक्तियों के बिना समय स्लॉट बहिष्कृत करें:
अपडेट की गई क्वेरी सेट-रिटर्निंग फ़ंक्शन को भी स्थानांतरित करती है generate_series()
से
. तक सूची, जो पोस्टग्रेज 10 से पहले साफ-सुथरी है:
SELECT t.mac, sn.sn, t.loc, ts.ts::time AS time, ts.ts::date AS date
, t.vin1_av, t.vin2_av, t.vin3_av
FROM (SELECT text '4as11111111') sn(sn) -- provide sn here once
CROSS JOIN LATERAL (
SELECT min(date+time) AS min_ts, max(date+time) AS max_ts
FROM tbl
WHERE sn = sn.sn
AND date+time >= '2018-01-01 0:0' -- provide time frame here
AND date+time < '2018-01-02 0:0'
) grid
CROSS JOIN LATERAL generate_series(min_ts, max_ts, interval '5 min') ts(ts)
CROSS JOIN LATERAL (
SELECT mac, loc
, round(avg(vin1)::numeric, 2) AS vin1_av -- cast to numeric for round()
, round(avg(vin2)::numeric, 2) AS vin2_av -- but rounding is optional
, round(avg(vin3)::numeric, 2) AS vin3_av
FROM tbl
WHERE sn = sn.sn
AND date+time >= ts.ts
AND date+time < ts.ts + interval '5 min'
GROUP BY mac, loc
HAVING count(*) > 0 -- exclude empty slots
) t;
इसका समर्थन करने के लिए एक बहु-स्तंभ अभिव्यक्ति अनुक्रमणिका बनाएं:
CRATE INDEX bar_idx ON tbl (sn, (date+time));
db<>fiddle यहां
लेकिन मैं इसके बजाय टाइमस्टैम्प
का अधिक उपयोग करूंगा साथ में।