(PostgreSQL 8.4)继续我之前的示例,我希望进一步了解使用窗口函数处理间隙和孤岛。考虑下表和数据:
CREATE TABLE T1
(
id SERIAL PRIMARY KEY,
val INT, -- some device
status INT -- 0=OFF, 1=ON
);
INSERT INTO T1 (val, status) VALUES (10, 0);
INSERT INTO T1 (val, status) VALUES (11, 0);
INSERT INTO T1 (val, status) VALUES (11, 1);
INSERT INTO T1 (val, status) VALUES (10, 1);
INSERT INTO T1 (val, status) VALUES (11, 0);
INSERT INTO T1 (val, status) VALUES (10, 0);
如前所述,设备会打开和关闭,这一次我希望提取一个特定的序列:
- 显示所有
ON
不重复的新状态记录(同一设备连续两次) OFF
从当前ON
设备显示适当的状态
我能得到的最接近的是:
SELECT * FROM (
SELECT *
,lag(val, 1, 0) OVER (PARTITION BY status ORDER BY id) last_val
,lag(status, 1, -1) OVER (PARTITION BY val ORDER BY id) last_status
FROM t1
) x
WHERE (last_val <> val OR last_status <> status)
AND (status = 1 OR last_status <> -1)
ORDER BY id
这会过滤掉样本不包含的更多虚假数据,但本质上是关于取出后续重复项(无论状态如何)和OFF
不匹配的顶级记录。Records 3
, 4
, 5
and6
被返回,但我不想要第五个,它OFF
是在 new 之后出现的ON
。所以我需要跳过这个差距并为OFF
当前活动的设备寻找下一个合适的设备。
- 10 关闭——在这种情况下是假的,但会弄乱 lag()
- 11 关闭——在这种情况下是假的,但会弄乱 lag()
- 11 开启 -- 好的,新序列,包含在 SELECT 中
- 10 次打开 -- 好的,新序列,包含在 SELECT 中
- 11 关闭——消息来晚了,需要忽略间隙
- 10 次关闭 -- 好的,正确关闭到第 4 行,需要包含在 SELECT 中
一旦正确过滤,我想lead()
在这一切之上使用来获取下一行的 id(想象一个时间戳)以及过滤掉所有不是ON
状态的记录。我想这将需要三个嵌入式 SELECT 语句。这将使我清楚地了解设备处于活动状态的时间,直到另一个ON
或适当转弯的条件OFF
。