sql >> データベース >  >> RDS >> PostgreSQL

特定の条件と適切なlead()の使用法を超えてSQLギャップをジャンプする

    ウィンドウ関数を使用したクエリ

    SELECT *
    FROM  (
       SELECT *
             ,lag(val, 1, 0)    OVER (PARTITION BY status ORDER BY id) AS last_val
             ,lag(status, 1, 0) OVER w2 AS last_status
             ,lag(next_id)      OVER w2 AS next_id_of_last_status
       FROM  (
          SELECT *, lead(id) OVER (PARTITION BY status ORDER BY id) AS next_id
          FROM   t1
          ) AS t
       WINDOW w2 AS (PARTITION BY val ORDER BY id)
      ) x
    WHERE (last_val <> val OR last_status <> status)
    AND   (status = 1 
           OR last_status = 1
              AND ((next_id_of_last_status > id) OR next_id_of_last_status IS NULL)
          )
    ORDER  BY id
    

    すでに持っていたもの に加えて 、有効なオフスイッチが必要です。

    オフ デバイスがONに切り替えられた場合、有効な場合は切り替えます 前( last_status =1 )および次の ON その後の操作はOFFの後に行われます 問題のスイッチ( next_id_of_last_status> id

    最後のONがあったという特別な場合に備えなければなりません 操作なので、 NULLをチェックします さらに( OR next_id_of_last_status IS NULL

    next_id_of_last_status last_statusと同じウィンドウから取得します から。したがって、明示的なウィンドウ宣言用に追加の構文を導入したので、繰り返す必要はありません。

    WINDOW w2 AS (PARTITION BY val ORDER BY id)
    

    そして、以前にサブクエリの最後のステータスの次のIDを取得する必要があります(サブクエリ t

    すべてを理解している場合 Lead()を叩くのに問題はないはずです このクエリに加えて、最終目的地に到達します。 :)

    PL/pgSQL関数

    これが複雑になったら、手続き型処理に切り替えます。

    この比較的単純なplpgsql関数 テーブル全体を1回だけスキャンする必要があるという単純な理由から、複雑なウィンドウ関数クエリのパフォーマンスを低下させます。

    CREATE OR REPLACE FUNCTION valid_t1 (OUT t t1)  -- row variable of table type
      RETURNS SETOF t1 LANGUAGE plpgsql AS
    $func$
    DECLARE
       _last_on int := -1;  -- init with impossible value
    BEGIN
    
    FOR t IN
       SELECT * FROM t1 ORDER BY id
    LOOP
       IF t.status = 1 THEN
          IF _last_on <> t.val THEN
             RETURN NEXT;
             _last_on := t.val;
          END IF;
       ELSE
          IF _last_on = t.val THEN
             RETURN NEXT;
             _last_on := -1;
          END IF;
       END IF;
    END LOOP;
    
    END
    $func$;
    

    電話:

    SELECT * FROM valid_t1();
    



    1. 米国の日付形式をANSISQLの日付形式に変換する(YYYY-mm-dd)

    2. このSQLINSERTステートメントが構文エラーを返すのはなぜですか?

    3. オブジェクト 'Address'、データベース 'CNET_85731'、スキーマ 'dbo' で SELECT 権限が拒否されました

    4. SQLServerのユーザー定義関数からエラーを報告する方法