(PostgreSQL 8.4)我对SQL gap-and-islands here on Stack Overflow进行了很好的介绍,但我还有一个问题。许多岛检测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
代表ON
或OFF
。我想使用以下逻辑选择记录1
,3
,6
,7
和9
。
基本上,一次只能打开一个设备,“中断”条件是:
我正在寻找CTE形式的东西,没有游标。
答案 0 :(得分: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)
与之前相同,但这次结合了两个窗口函数。打开设备符合以下条件:
1.打开的最后一个设备是不同的
2.或者同一设备已在其最后一个条目中切换 off 。对于分区的第一行,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行。
根据你的描述,子查询忽略所有关闭,因为这只是噪音。留下设备开启的条目。其中,只有那些条目被取消资格,同一设备已经开启(最后一个条目开启)。使用window function lag()
即可。特别是我提供0
作为默认值来涵盖第一行的特殊情况 - 假设没有设备val = 0
。
如果有,请选择另一个不可能的数字
如果无法编号,请将特殊情况保留为NULL
lag(val) OVER ...
,并在外部查询中查看:
WHERE last_on IS DISTINCT FROM val