PostgreSQL
 sql >> डेटाबेस >  >> RDS >> PostgreSQL

ग्रुपिंग के पहले और आखिरी टाइमस्टैम्प के बीच किसी अन्य फ़ील्ड का अंतर प्राप्त करें

चरण 1:हैंडब्रेक छोड़ें

SELECT to_char(MIN(ts)::timestamptz, 'YYYY-MM-DD HH24:MI:SS TZ') AS min_time
      ,SUM(CASE WHEN sensor_id = 572 THEN value ELSE 0.0 END) AS nickname1
      ,SUM(CASE WHEN sensor_id = 542 THEN value ELSE 0.0 END) AS nickname2
      ,SUM(CASE WHEN sensor_id = 571 THEN value ELSE 0.0 END) AS nickname3
FROM   sensor_values
-- LEFT JOIN sensor_values_cleaned s2 USING (sensor_id, ts)
WHERE  ts >= '2013-10-14T00:00:00+00:00'::timestamptz::timestamp
AND    ts <  '2013-10-18T00:00:00+00:00'::timestamptz::timestamp
AND    sensor_id IN (572, 542, 571, 540, 541, 573)
GROUP  BY ts::date AS day
ORDER  BY 1;

प्रमुख बिंदु

  • आरक्षित शब्द बदलें (मानक SQL में) आपके पहचानकर्ताओं में।
    timestamp -> ts
    time -> min_time

  • चूंकि जॉइन समान कॉलम नामों पर होता है, इसलिए आप सरल USING खंड शामिल होने की स्थिति में:USING (sensor_id, ts)
    हालांकि, दूसरी तालिका के बाद से sensor_values_cleaned इस क्वेरी के लिए 100% अप्रासंगिक है, मैंने इसे पूरी तरह से हटा दिया है।

  • जैसा कि @joop ने पहले ही सलाह दी है, स्विच करें min() और to_char() आपके पहले आउट पुट कॉलम में। इस तरह, Postgres मूल स्तंभ मान . से न्यूनतम निर्धारित कर सकते हैं , जो आम तौर पर तेज़ होता है और एक इंडेक्स का उपयोग करने में सक्षम हो सकता है। इस विशिष्ट मामले में, date के अनुसार आदेश देना text . द्वारा ऑर्डर करने से भी सस्ता है , जिसे मिलान नियमों पर भी विचार करना होगा।

  • इसी तरह का विचार आपके WHERE . पर भी लागू होता है शर्त:
    WHERE ts::timestamptz>='2013-10-14T00:00:00+00:00'::timestamptz

    WHERE  ts >= '2013-10-14T00:00:00+00:00'::timestamptz::timestamp
    

    दूसरा है sargable और ts . पर एक सादे अनुक्रमणिका का उपयोग कर सकते हैं - बड़ी तालिकाओं में प्रदर्शन पर बहुत प्रभाव के लिए!

  • ts::date . का उपयोग करना के बजाय date_trunc('day', ts) . सरल, तेज, समान परिणाम।

  • संभवत:आपकी दूसरी WHERE स्थिति थोड़ी गलत है। आम तौर पर, आप ऊपरी सीमा को छोड़ देंगे :

    AND    ts <=  '2013-10-18T00:00:00+00:00' ...

    AND    ts <   '2013-10-18T00:00:00+00:00' ...
  • timestamp मिलाते समय और timestamptz किसी को प्रभावों के बारे में पता होना चाहिए। उदाहरण के लिए, आपका WHERE कंडीशन 00:00 स्थानीय समय पर नहीं कटती है (सिवाय इसके कि स्थानीय समय यूटीसी के साथ मेल खाता हो)। विवरण यहाँ:
    रेल और पोस्टग्रेएसक्यूएल में टाइमज़ोन को पूरी तरह से नज़रअंदाज़ करना

चरण 2:आपका अनुरोध

और इससे मुझे लगता है कि आपका मतलब है:
... के मान . के बीच का अंतर नवीनतम और शुरुआती टाइमस्टैम्प ...
अन्यथा यह बहुत आसान होगा।

विंडो फ़ंक्शन का उपयोग करें उसके लिए, विशेष रूप से first_value() और last_value() . संयोजन के साथ सावधान, आप एक गैर चाहते हैं -मानक विंडो फ्रेम इस मामले में last_value() के लिए। तुलना करें:
PostgreSQL एग्रीगेट या विंडो फ़ंक्शन केवल अंतिम मान लौटाने के लिए

मैं इसे <मजबूत>DISTINCT ON , जो इस मामले में GROUP BY . की तुलना में अधिक सुविधाजनक है (जिसे एक और सबक्वेरी स्तर की आवश्यकता होगी):

SELECT DISTINCT ON (ts::date, sensor_id)
       ts::date AS day
      ,to_char((min(ts)  OVER (PARTITION BY ts::date))::timestamptz
              ,'YYYY-MM-DD HH24:MI:SS TZ') AS min_time
      ,sensor_id
      ,last_value(value)    OVER (PARTITION BY ts::date, sensor_id ORDER BY ts
                     RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
       - first_value(value) OVER (PARTITION BY ts::date, sensor_id ORDER BY ts)
                                                                   AS val_range
FROM   sensor_values
WHERE  ts >= '2013-10-14T00:00:00+0'::timestamptz::timestamp
AND    ts <  '2013-10-18T00:00:00+0'::timestamptz::timestamp
AND    sensor_id IN (540, 541, 542, 571, 572, 573)
ORDER  BY ts::date, sensor_id;

-> SQLfiddle डेमो।

चरण 3:पिवट टेबल

उपरोक्त क्वेरी के आधार पर मैं crosstab() अतिरिक्त मॉड्यूल से tablefunc :

SELECT * FROM crosstab(
   $$SELECT DISTINCT ON (1,3)
            ts::date AS day
           ,to_char((min(ts) OVER (PARTITION BY ts::date))::timestamptz,'YYYY-MM-DD HH24:MI:SS TZ') AS min_time
           ,sensor_id
           ,last_value(value)    OVER (PARTITION BY ts::date, sensor_id ORDER BY ts RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
            - first_value(value) OVER (PARTITION BY ts::date, sensor_id ORDER BY ts) AS val_range
     FROM   sensor_values
     WHERE  ts >= '2013-10-14T00:00:00+0'::timestamptz::timestamp
     AND    ts <  '2013-10-18T00:00:00+0'::timestamptz::timestamp
     AND    sensor_id IN (540, 541, 542, 571, 572, 573)
     ORDER  BY 1, 3$$

   ,$$VALUES (540), (541), (542), (571), (572), (573)$$
   )
AS ct (day date, min_time text, s540 numeric, s541 numeric, s542 numeric, s571 numeric, s572 numeric, s573 numeric);

रिटर्न (और बहुत पहले से तेज):

    day     |         min_time         | s540  | s541  | s542  | s571  | s572  | s573
------------+--------------------------+-------+-------+-------+-------+-------+-------
 2013-10-14 | 2013-10-14 03:00:00 CEST | 18.82 | 18.98 | 19.97 | 19.47 | 17.56 | 21.27
 2013-10-15 | 2013-10-15 00:15:00 CEST | 22.59 | 24.20 | 22.90 | 21.27 | 22.75 | 22.23
 2013-10-16 | 2013-10-16 00:16:00 CEST | 23.74 | 22.52 | 22.23 | 23.22 | 23.03 | 22.98
 2013-10-17 | 2013-10-17 00:17:00 CEST | 21.68 | 24.54 | 21.15 | 23.58 | 23.04 | 21.94


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. PostgreSQL में डिग्री () फ़ंक्शन कैसे काम करता है

  2. मैं अपने द्वारा बनाए गए भौतिक दृश्य की अंतर्निहित क्वेरी को कैसे खोजूं?

  3. बाल्टियों में वस्तुओं को छांटना वैध JPQL अभिव्यक्ति के रूप में कैसे तैयार किया जा सकता है?

  4. अद्यतन का FROM पक्ष अद्यतन के लिए लक्षित तालिका से कैसे संबंधित है?

  5. कोड कवरेज आँकड़े