如何解决SQL:检测具有相同键的连续行的连续块
我的问题归结为以下几点。我有一个带有一些自然排序的表,其中我有一个可能会随着时间重复的键值。我想找到键相同的块,然后更改,然后恢复相同。示例:
- A
- A
- B
- B
- B
- C
- C
- A
- A
- C
- C
这里是我想要的结果
- A,1-2
- B,3-5
- C,6-7
- A,8-9
- C,10-11
所以我不能使用那个键值 A、B、C 来分组,因为同一个键可以出现多次,我只想挤出不间断的重复出现。
不用说,我想要一个可以想出的最简单的 sql。它将使用 OLAP 窗口函数。
我通常很擅长复杂的 sql,但对于序列我不太擅长。当然,我会自己做一些工作,并在随后的编辑中在这个问题下面附上一些想法。
让我们首先定义我们讨论的表格:
CREATE TABLE Seq (
num integer,key char
);
更新 1:做一些研究我在这里发现了一个类似的问题:How to find consecutive rows based on the value of a column? 但问题和答案都包含在很多额外的东西中并且令人困惑。
更新 2:我已经得到了一个答案,谢谢。现在正在检查。这是我的测试,即使我们说话,我也正在输入 Postgresql:
CREATE TABLE Seq ( num int,key char );
INSERT INTO Seq VALUES
(1,'A'),(2,'B'),(3,(5,(6,'C'),(7,(8,(9,(10,(11,'C');
SELECT key,min(num),max(num)
FROM (
SELECT seq.*,row_number() over (partition by key order by num) as seqnum
FROM Seq
) s
GROUP BY key,(num - seqnum)
ORDER BY min;
产量:
key | min | max
-----+-----+-----
A | 1 | 2
B | 2 | 3
B | 5 | 5
C | 6 | 7
A | 8 | 9
C | 10 | 11
(6 rows)
出于某种原因,B 重复了两次,我明白为什么,我在测试数据中犯了一个“错误”,跳过序列 num 4 并直接从 3 到 5。
这个错误是幸运的,因为它允许我指出,虽然在这个例子中序列号是离散的,但我希望序列来自某个连续域(例如时间)。
我犯了另一个“错误”,因为我重复了 num 2。这是允许的吗?可能不是。所以清理示例,删除重复但留下空白:
DROP TABLE Seq;
CREATE TABLE Seq ( num int,(4,(12,'C');
这仍然给我们留下了重复的 B 块:
key | min | max
-----+-----+-----
A | 1 | 2
B | 3 | 4
B | 6 | 6
C | 7 | 8
A | 9 | 10
C | 11 | 12
(6 rows)
现在根据 Gordon Linoff 的第一个直觉来尝试理解它并添加进去:
SELECT s.*,num - seqnum AS diff
FROM (
SELECT seq.*,row_number() over (partition by key order by num) as seqnum
FROM Seq
) s
ORDER BY num;
这是分组前的 num - seqnum 技巧:
num | key | seqnum | diff
-----+-----+--------+------
1 | A | 1 | 0
2 | A | 2 | 0
3 | B | 1 | 2
4 | B | 2 | 2
6 | B | 3 | 3
7 | C | 1 | 6
8 | C | 2 | 6
9 | A | 3 | 6
10 | A | 4 | 6
11 | C | 3 | 8
12 | C | 4 | 8
(11 rows)
我怀疑这是否是答案。
解决方法
这回答了原来的问题。
您可以枚举每个键的行并从 num
中减去它。瞧!当相邻行上的 key
为常量时,此数字为常量:
select key,min(num),max(num)
from (select seq.*,row_number() over (partition by key order by num) as seqnum
from seq
) s
group by key,(num - seqnum);
Here 是一个 dbfiddle,表明它有效。
,由于存在间隙,您不能像 Gordon 的解决方案建议的那样直接使用 num
。 Row_number
也是。
select key,row_number() over (order by num) as rn,(rn - seqnum)
order by min(num);
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。