3

(PostgreSQL 8.4)ここStack OverflowでSQLのギャップと島についてのすばらしい紹介がありましたが、まだ質問があります。多くのアイランド検出CTEは、タイムスタンプの実行順序と、シーケンスが変更されたときにシーケンスを中断するフラグに基づいています。しかし、「ブレーク」状態がもう少し複雑な場合はどうなるでしょうか。

CREATE TABLE T1
(
  id SERIAL PRIMARY KEY,
  val INT,   -- some device
  status INT -- 0=OFF, 1=ON
);

INSERT INTO T1 (val, status) VALUES (10, 1);
INSERT INTO T1 (val, status) VALUES (10, 0);
INSERT INTO T1 (val, status) VALUES (11, 1);
INSERT INTO T1 (val, status) VALUES (11, 1);
INSERT INTO T1 (val, status) VALUES (10, 0);
INSERT INTO T1 (val, status) VALUES (12, 1);
INSERT INTO T1 (val, status) VALUES (13, 1);
INSERT INTO T1 (val, status) VALUES (13, 0);
INSERT INTO T1 (val, status) VALUES (13, 1);

この場合、valはデバイスを表し、またはのstatusいずれONOFFです。次のロジックでレコード1、、、3を選択したいと思います。679

  1. 10がオンになります-OK、新しいシーケンス、SELECTに含める

  2. 10がオフになります-シーケンスを適切に終了し、行を無視します

  3. 11がオンになります-OK、新しいシーケンス、SELECTに含めます

  4. 11がオンになります-重複し、行を無視します

  5. 10がオフになります-#10はオンになりませんでした、無視してください

  6. 12がオンになります-OK、暗黙的にオフになります#11、SELECTに含めます

  7. 13がオンになります-OK、暗黙的にオフになります#12、SELECTに含めます

  8. 13がオフになります-シーケンスを適切に終了し、行を無視します

  9. 13がオンになります-OK、新しいシーケンス、SELECTに含める

基本的に、一度にオンにできるデバイスは1つだけであり、「ブレーク」状態は次のとおりです。

  • new.val = running.val AND new.status = 0
  • new.val <> running.val AND new.status = 1

CTEの形で何かを探しています。カーソルはありません

4

1 に答える 1

2

更新された質問に対する回答

SELECT *
FROM  (
   SELECT *
         ,lag(val, 1, 0) OVER (PARTITION BY status ORDER BY id) last_val
         ,lag(status) OVER (PARTITION BY val ORDER BY id) last_status
   FROM   t1
   ) x
WHERE  status = 1
AND    (last_val <> val OR last_status = 0)

どのように?

前と同じですが、今回は 2 つのウィンドウ関数を組み合わせます。
1. 最後に電源を入れたデバイスがのデバイスであった場合、デバイスの電源を入れることは資格があります。
2. または、同じデバイスが最後のエントリでオフになっています。NULLパーティションの最初の行ののコーナー ケースは、その行が1 で既に修飾されているため、無関係です。


質問の元のバージョンの回答。

あなたのタスクを正しく理解していれば、次の簡単なクエリで仕事ができます。

SELECT *
FROM  (
   SELECT *
         ,lag(val, 1, 0) OVER (ORDER BY id) last_on
   FROM   t1
   WHERE  status = 1
   ) x
WHERE  last_on <> val

要求に応じて行 1、3、6、7 を返します。

どのように?

あなたの説明によると、サブクエリはすべてのスイッチオフを無視します。これは単なるノイズであるためです。デバイスがオンになっているエントリを残します。その中で、同じデバイスがすでにオンになっているエントリのみが失格となります (最後にオンになったエントリ)。そのためにウィンドウ関数lag()を使用します。特に0、最初の行の特殊なケースをカバーするためにデフォルトとして提供します - を備えたデバイスがないと仮定しval = 0ます。
ある場合は、別の不可能な番号を選択します。
不可能な数値がない場合は、特別なケースをそのままにしNULLlag(val) OVER ...外側のクエリで次のようにチェックします。

WHERE last_on IS DISTINCT FROM val
于 2012-09-17T22:08:11.830 に答える