ステップ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)
ただし、2番目のテーブルsensor_values_cleaned
以降 このクエリとは100%無関係なので、完全に削除しました。 -
@joopがすでにアドバイスしているように、
min()
を切り替えます およびto_char()
最初の出力列に。このようにして、Postgresは元の列の値から最小値を決定できます。 、一般的に高速で、インデックスを利用できる場合があります。この特定のケースでは、date
text
で注文するよりも安いです 、照合ルールも考慮する必要があります。 -
同様の考慮事項が
WHERE
にも当てはまります 条件:
WHERE ts ::timestamptz> ='2013-10-14T00:00:00 + 00:00' ::timestamptzWHERE ts >= '2013-10-14T00:00:00+00:00'::timestamptz::timestamp
2つ目は、 sargable
ts
のプレーンインデックスを利用できます -大きなテーブルのパフォーマンスに大きな影響を与えます! -
ts::date
の使用date_trunc('day', ts)
の代わりに 。よりシンプル、高速、同じ結果。 -
おそらく、2番目のWHERE条件が少し間違っています。通常、上部の境界線を除外します :
ストライク>AND ts <= '2013-10-18T00:00:00+00:00' ...
AND ts < '2013-10-18T00:00:00+00:00' ...
-
timestamp
をミキシングする場合 およびtimestamptz
影響に注意する必要があります。たとえば、WHERE
条件は現地時間の00:00にカットされません(現地時間がUTCと一致する場合を除く)。詳細はこちら:
RailsとPostgreSQLでタイムゾーンを完全に無視する
ステップ2:リクエスト
そして、それはあなたが意味していると思います:
...の価値の違い 最新および最古のタイムスタンプ...
そうでない場合は、はるかに簡単になります。
ウィンドウ関数を使用します
そのために、特にfirst_value()
およびlast_value()
。組み合わせに注意して、 non -標準のウィンドウフレーム
この場合、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;
ステップ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