2012-10-22 3 views
7

में दिनांक और समय के माध्यम से एकत्रीकरण करना मेरे पास डेटा-सेट है जिसमें कई सप्ताह के लिए 2 मिनट आवृत्ति के साथ अवलोकन शामिल हैं। मैं 2 मिनट से 5 मिनट तक समय अंतराल बढ़ाना चाहता हूं। समस्या यह है कि, अवलोकनों की आवृत्ति हमेशा एक जैसी नहीं होती है। मेरा मतलब है, सैद्धांतिक रूप से, हर 10 मिनट में 5 अवलोकन होना चाहिए लेकिन आमतौर पर यह मामला नहीं है। कृपया मुझे बताएं कि मैं औसत कार्य के आधार पर और अवलोकनों के समय और तिथि के संबंध में अवलोकनों को कैसे एकत्र कर सकता हूं। दूसरे शब्दों में प्रत्येक 5 मिनट के आधार पर एकत्रीकरण, जबकि प्रत्येक 5 मिनट के अंतराल के लिए अवलोकनों की संख्या समान नहीं होती है। इसके अलावा, मेरे पास टाइमस्टैम्प प्रारूप में दिनांक और समय है।एसक्यूएल

उदाहरण डेटा:

1 2007-09-14 22:56:12 5.39 
2 2007-09-14 22:58:12 5.34 
3 2007-09-14 23:00:12 5.16 
4 2007-09-14 23:02:12 5.54 
5 2007-09-14 23:04:12 5.30 
6 2007-09-14 23:06:12 5.20 

अपेक्षित परिणाम:

1 2007-09-14 23:00 5.29 
2 2007-09-14 23:05 5.34 
+0

पोस्ट नमूना डेटा: आपके पास क्या है, आपको क्या चाहिए। एक नमूना परीक्षण करने के लिए आसान होने के लिए इसे आवेषण कथन के रूप में लिखें। साथ ही, हमें बताएं कि आप किस डेटाबेस ब्रांड का उपयोग कर रहे हैं। – danihp

+0

@danihp डेटा नमूना: [1 2007-09-14 22:56:12 5.3 9 2 2007-09-14 22:58:12 5.34 3 2007-09-14 23:00:12 5.16 4 2007-09 -14 23:02:12 5.54 5 2007-09-14 23:04:12 5.30 6 2007-09-14 23:06:12 5.20] अपेक्षित परिणाम: 1 2007-09-14 23:00 5.2 9 2 2007-09-14 23:06 5.34, मैं PostgreSQL –

+2

@aliamidi का उपयोग कर रहा हूं - आपको वास्तव में इस तरह की जानकारी को प्रश्न में रखना चाहिए, टिप्पणी नहीं। मैंने आपके लिए प्रश्न में किए गए संपादन को देखें ... इसके अलावा, कृपया आप समझा सकते हैं कि आउटपुट की अपेक्षा की गई क्यों है? दूसरा रिकॉर्ड '23: 06' और' 23: 05' क्यों नहीं है? और अपेक्षित '5.34' कहां से आते हैं? – MatBailie

उत्तर

6

this question के उत्तर आपकी समस्या के लिए अच्छे समाधान प्रदान करते हैं, जो समय खिड़कियों में डेटा को कुशलतापूर्वक एकत्र करने के तरीके दिखाते हैं।

GROUP BY floor(extract(epoch from the_timestamp)/60/5) 
1

अब तक सबसे आसान विकल्प के लिए एक संदर्भ तालिका बनाने के लिए है। उस तालिका में आप अंतराल जिस पर आप insterested कर रहे हैं की दुकान: (। अपने खुद के आरडीबीएमएस की तारीख अंकन को यह अनुकूलन)

CREATE TABLE interval (
    start_time DATETIME, 
    cease_time DATETIME 
); 
INSERT INTO interval SELECT '2012-10-22 12:00', '2012-10-22 12:05'; 
INSERT INTO interval SELECT '2012-10-22 12:05', '2012-10-22 12:10'; 
INSERT INTO interval SELECT '2012-10-22 12:10', '2012-10-22 12:15'; 
INSERT INTO interval SELECT '2012-10-22 12:15', '2012-10-22 12:20'; 
INSERT INTO interval SELECT '2012-10-22 12:20', '2012-10-22 12:25'; 
INSERT INTO interval SELECT '2012-10-22 12:25', '2012-10-22 12:30'; 
INSERT INTO interval SELECT '2012-10-22 12:30', '2012-10-22 12:35'; 
INSERT INTO interval SELECT '2012-10-22 12:35', '2012-10-22 12:40'; 

तो फिर तुम बस में शामिल होने और कुल ...

SELECT 
    interval.start_time, 
    AVG(observation.value) 
FROM 
    interval 
LEFT JOIN 
    observation 
    ON observation.timestamp >= interval.start_time 
    AND observation.timestamp < interval.cease_time 
GROUP BY 
    interval.start_time 

नोट: आपको केवल उस अंतराल तालिका को बनाने और पॉप्युलेट करने की आवश्यकता है, फिर आप इसे कई बार फिर से उपयोग कर सकते हैं।

+1

'सम्मिलित करें ... का चयन करें' का उपयोग करके जटिल डालने का क्यों? एक साधारण 'मान' खंड बहुत अधिक straighforward –

+0

है मैं @a_horse_with_no_name से सहमत हूं; कि 'डालें ... चुनें' काफी विषम है। एक 'मूल्य (' पहला ',' पंक्ति '), (' दूसरा ',' पंक्ति ');' सूची बहुत स्पष्ट और सरल है। मूल्यों को हाथ से उत्पादित करना अजीब है जब आप आधार संख्या में मिनटों में अंतराल जोड़ने के लिए 'gener_series' का उपयोग कर सकते हैं। –

2

संपादित करें:

अनिवार्य रूप से, के साथ avg कुल का उपयोग मैं इस बारे में कुछ और सोच किया और महसूस किया कि आप न सिर्फ 5 मिनट के लिए 2 मिनट से जा सकते हैं। यह जोड़ नहीं है। मैं उस पर फॉलो-अप करूंगा, लेकिन एक बार आपके पास कुल 1-मिनट डेटा होने के बाद निम्न कोड काम करता है!

-

डेटा एक 'शुरुआत' प्रारूप में है, तो आप इस समारोह के अंदर कोड का उपयोग कर सकते हैं, या अपने डेटाबेस पर समारोह का उपयोग में आसानी के लिए बनाने के लिए:

CREATE OR REPLACE FUNCTION dev.beginning_datetime_floor(timestamp without time zone, 
integer) /* switch out 'dev' with your schema name */ 
RETURNS timestamp without time zone AS 
$BODY$ 
SELECT 
date_trunc('minute',timestamp with time zone 'epoch' + 
floor(extract(epoch from $1)/($2*60))*$2*60 
* interval '1 second') at time zone 'CST6CDT' /* change this to your time zone */ 
$BODY$ 
LANGUAGE sql VOLATILE; 

तुम बस

select dev.beginning_datetime_floor('2012-01-01 02:02:21',2) 

: यह आप पर इकट्ठा करना चाहते हैं मिनट के पूर्णांक संख्या (प्रयोग 1, 2, 3, 4, 5, 6, 10, 12, 15, 20, या 30) को खिलाने के लिए, यहाँ एक जोड़ी परिणाम है = '2012-01-01 02:02:00'

select dev.beginning_datetime_floor('2012-01-01 02:02:21',5) 

= '2012-01-01 02:00:00'

बस इसे बाहर का परीक्षण करने और जोड़ने के लिए या built-in timestamp functions का उपयोग कर timestamps न खत्म होने वाली बनाम शुरुआत को संभालने के लिए समय घटाना।

जब आप अपना इच्छित टाइमस्टैम्प प्राप्त करते हैं, तो क्रेग ने कहा, और उस टाइमस्टैम्प पर ग्रुप बाय, वांछित aggregate functions (संभावित औसत) के संयोजन के साथ करें।

आप परीक्षण कर सकते हैं/साथ यह tweak: यह बाहर बारी सकता है कि आप टाइम स्टांप औसत करने के लिए चाहते हैं

date_trunc('minute',timestamp with time zone 'epoch' + 
floor(extract(epoch from your_datetime)/(interval_minutes*60))*interval_minutes*60 
* interval '1 second') at time zone 'CST6CDT' /* change this to your time zone */ 

- अगर आपकी अंतराल अवधि उदाहरण के लिए अस्थिर है। इसके लिए, आप एक समान कार्य कर सकते हैं जो फर्श लेने के बजाए टाइमस्टैम्प को घेरता है।

1

ठीक है, तो यह इसे संभालने का एक ही तरीका है। मुझे उम्मीद है कि यह आपको विश्लेषण आवश्यकताओं के लिए डेटा को परिवर्तित करने के तरीके के बारे में सोचता है।

इस कोड का परीक्षण करने के लिए एक और आवश्यकता है। आपको सभी संभव 1-मिनट की टाइमस्टैम्प के साथ एक टेबल की आवश्यकता है। इसके बारे में जाने के कई तरीके हैं, मैं केवल जो कुछ उपलब्ध हूं उसका उपयोग करूंगा, जो एक टेबल है: dim_time जिसमें प्रत्येक मिनट (00:01:00) (23:59:00) और सभी संभवतानुसार एक और तालिका है तिथियां (dim_date)। जब आप इन (1 = 1) में शामिल होते हैं तो आपको सभी संभावित दिनों के लिए सभी संभव मिनट मिलते हैं।

--first you need to create some functions I'll use later 
--credit to this first function goes to David Walling 
CREATE OR REPLACE FUNCTION dev.beginning_datetime_floor(timestamp without time zone, integer) 
    RETURNS timestamp without time zone AS 
$BODY$ 
SELECT 
date_trunc('minute',timestamp with time zone 'epoch' + 
    floor(extract(epoch from $1)/($2*60))*$2*60 
* interval '1 second') at time zone 'CST6CDT' 
$BODY$ 
    LANGUAGE sql VOLATILE; 

--the following function is what I described on my previous post 
CREATE OR REPLACE FUNCTION dev.round_minutes(timestamp without time zone, integer) 
    RETURNS timestamp without time zone AS 
$BODY$ 
    SELECT date_trunc('hour', $1) + cast(($2::varchar||' min') as interval) * round(date_part('minute',$1)::float/cast($2 as float)) 
$BODY$ 
    LANGUAGE sql VOLATILE; 

--let's load the data into a temp table, I added some data points. note: i got rid of the partial seconds 
SELECT cast(timestamp_original as timestamp) as timestamp_original, datapoint INTO TEMPORARY TABLE timestamps_second2 
FROM 
(
SELECT '2007-09-14 22:56:12' as timestamp_original, 0 as datapoint 
UNION 
SELECT '2007-09-14 22:58:12' as timestamp_original, 1 as datapoint 
UNION 
SELECT '2007-09-14 23:00:12' as timestamp_original, 10 as datapoint 
UNION 
SELECT '2007-09-14 23:02:12' as timestamp_original, 100 as datapoint 
UNION 
SELECT '2007-09-14 23:04:12' as timestamp_original, 1000 as datapoint 
UNION 
SELECT '2007-09-14 23:06:12' as timestamp_original, 10000 as datapoint 
) as data 

--this is the bit of code you'll have to replace with your implementation of getting all possible minutes 
--you could make some sequence of timestamps in R, or simply make the timestamps in Excel to test out the rest of the code 
--the result of the query is simply '2007-09-14 00:00:00' through '2007-09-14 23:59:00' 
SELECT * INTO TEMPORARY TABLE possible_timestamps 
FROM 
(
select the_date + beginning_minute as minute_timestamp 
FROM datawarehouse.dim_date as dim_date 
JOIN datawarehouse.dim_time as dim_time 
ON 1=1 
where dim_date.the_date = '2007-09-14' 
group by the_date, beginning_minute 
order by the_date, beginning_minute 
) as data 

--round to nearest minute (be sure to think about how this might change your results 
SELECT * INTO TEMPORARY TABLE rounded_timestamps2 
FROM 
(
SELECT dev.round_minutes(timestamp_original,1) as minute_timestamp_rounded, datapoint 
from timestamps_second2 
) as data 

--let's join what minutes we have data for versus the possible minutes 
--I used some subqueries so when you select all from the table you'll see the important part (not needed) 
SELECT * INTO TEMPORARY TABLE joined_with_possibles 
FROM 
(
SELECT * 
FROM 
(
SELECT *, (MIN(minute_timestamp_rounded) OVER()) as min_time, (MAX(minute_timestamp_rounded) OVER()) as max_time 
FROM possible_timestamps as t1 
LEFT JOIN rounded_timestamps2 as t2 
ON t1.minute_timestamp = t2.minute_timestamp_rounded 
ORDER BY t1.minute_timestamp asc 
) as inner_query 
WHERE minute_timestamp >= min_time 
AND minute_timestamp <= max_time 
) as data 

--here's the tricky part that might not suit your needs, but it's one method 
--if it's missing a value it grabs the previous value 
--if it's missing the prior value it grabs the one before that, otherwise it's null 
--best practice would be run another case statement with 0,1,2 specifying which point was pulled, then you can count those when you aggregate 
SELECT * INTO TEMPORARY TABLE shifted_values 
FROM 
(
SELECT 
*, 
case 
when datapoint is not null then datapoint 
when datapoint is null and (lag(datapoint,1) over (order by minute_timestamp asc)) is not null 
    then lag(datapoint,1) over (order by minute_timestamp asc) 
when datapoint is null and (lag(datapoint,1) over (order by minute_timestamp asc)) is null and (lag(datapoint,2) over (order by minute_timestamp asc)) is not null 
    then lag(datapoint,2) over (order by minute_timestamp asc) 
else null end as last_good_value 
from joined_with_possibles 
ORDER BY minute_timestamp asc 
) as data 

--now we use the function from my previous post to make the timestamps to aggregate on 
SELECT * INTO TEMPORARY TABLE shifted_values_with_five_minute 
FROM 
(
SELECT *, dev.beginning_datetime_floor(minute_timestamp,5) as five_minute_timestamp 
FROM shifted_values 
) as data 

--finally we aggregate 
SELECT 
AVG(datapoint) as avg_datapoint, five_minute_timestamp 
FROM shifted_values_with_five_minute 
GROUP BY five_minute_timestamp