PostgreSQL
 sql >> Teknologi Basis Data >  >> RDS >> PostgreSQL

Dapatkan perbedaan bidang lain antara stempel waktu pengelompokan pertama dan terakhir

Langkah 1:Lepaskan rem tangan

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;

Poin utama

  • Ganti kata khusus (dalam SQL standar) di pengidentifikasi Anda.
    timestamp -> ts
    time -> min_time

  • Karena gabungan menggunakan nama kolom yang identik, Anda dapat menggunakan USING klausa dalam kondisi join:USING (sensor_id, ts)
    Namun, sejak tabel kedua sensor_values_cleaned 100% tidak relevan dengan kueri ini, saya menghapusnya sepenuhnya.

  • Seperti yang sudah disarankan @joop, alihkan min() dan to_char() di kolom out put pertama Anda. Dengan cara ini, Postgres dapat menentukan minimum dari nilai kolom asli , yang umumnya lebih cepat dan mungkin dapat menggunakan index. Dalam kasus khusus ini, memesan berdasarkan date juga lebih murah daripada memesan dengan text , yang juga harus mempertimbangkan aturan pengumpulan.

  • Pertimbangan serupa berlaku untuk WHERE . Anda kondisi:
    WHERE ts::timestamptz>='2013-10-14T00:00:00+00:00'::timestamptz

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

    Yang kedua adalah sargable dan dapat menggunakan indeks biasa pada ts - sangat berpengaruh pada performa di tabel besar!

  • Menggunakan ts::date bukannya date_trunc('day', ts) . Lebih sederhana, lebih cepat, hasil yang sama.

  • Kemungkinan besar kondisi WHERE kedua Anda sedikit salah. Umumnya, Anda akan mengecualikan batas atas :

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

    AND    ts <   '2013-10-18T00:00:00+00:00' ...
  • Saat mencampur timestamp dan timestamptz seseorang perlu menyadari efeknya. Misalnya, WHERE . Anda ketentuan tidak dipotong pada pukul 00:00 waktu setempat (kecuali jika waktu setempat bertepatan dengan UTC). Detailnya di sini:
    Mengabaikan zona waktu sama sekali di Rails dan PostgreSQL

Langkah 2:Permintaan Anda

Dan dengan itu saya kira maksud Anda:
...perbedaan antara nilai stempel waktu terbaru dan paling awal ...
Jika tidak, akan jauh lebih sederhana.

Gunakan fungsi jendela untuk itu, khususnya first_value() dan last_value() . Hati-hati dengan kombinasinya, Anda menginginkan non -bingkai jendela standar untuk last_value() dalam kasus ini. Bandingkan:
Agregat PostgreSQL atau fungsi jendela untuk mengembalikan nilai terakhir saja

Saya menggabungkan ini dengan DISTINCT ON , yang lebih nyaman dalam hal ini daripada GROUP BY (yang akan membutuhkan level subquery lain):

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;

-> Demo SQLfiddle.

Langkah 3:Tabel pivot

Berdasarkan kueri di atas, saya menggunakan crosstab() dari modul tambahan 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);

Pengembalian (dan banyak lebih cepat dari sebelumnya):

    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. Segarkan tampilan yang terwujud dengan konkurensi

  2. offset/batas optimalisasi kinerja

  3. Apakah mungkin untuk mendefinisikan variabel global di postgresql

  4. Melihat database di Heroku

  5. Bagaimana saya bisa meninjau semua database dan hibah objek untuk suatu peran?