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)
      ただし、2番目のテーブル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
      

      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;
    

    ->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. Hibernate + c3p0 + MySqlが多数のスリープ接続を作成するのを防ぐにはどうすればよいですか?

    2. 保存したlocalStorageWebデータをphpスクリプトに渡すにはどうすればよいですか?

    3. 壊れたCSV、どうすれば修正できますか?

    4. Oracle:有効な月ではありません