[英]Find all records within x units of each other
我有一张这样的表:
CREATE TABLE t(idx integer primary key, value integer);
INSERT INTO t(idx, value)
VALUES
(1, 1),
(2, 2),
(3, 3),
(4, 6),
(5, 7),
(6, 12)
我想返回值彼此相差在 2 以内的所有记录组,并使用关联的组标签作为新列来识别它们。
我想也许递归查询可能是合适的......但我的 sql-fu 是缺乏的。
我假设您想对行进行分组,以便每个组中的任何两个值最多只能相差 2。那么您是对的,递归查询就是解决方案。 在每一级递归中,新组的边界都被预先计算。 组是不相交的,所以最后用计算出的组号加入原始表,然后按这个号分组。 数据库小提琴在这里。
with recursive r (minv,maxv,level) as (
select min(t.value), min(t.value) + 2, 1
from t
union all
select minv, maxv, level from (
select t.value as minv, t.value + 2 as maxv, r.level + 1 as level, row_number() over (order by minv) rn
from r
join t on t.value > r.maxv
) x where x.rn = 1
)
select r.level
, format('ids from %s to %s', min(t.idx), max(t.idx)) as id_label
, format('values from %s to %s', min(t.value), max(t.value)) as value_label
from t join r on t.value between r.minv and r.maxv
group by r.level
order by r.level
(递归部分的内部查询只是将新添加的行数限制为一个。更简单的子句select min(t.value), min(t.value) + 2
是不可能的,因为递归中不允许聚合函数部分,分析函数是解决方法。)
您可以使用递归 CTE:
with recursive tt as (
select t.*, row_number() over (order by idx) as seqnum
from t
),
cte as (
select idx, value, value as grp,
seqnum, 1 as lev
from tt
where seqnum = 1
union all
select tt.idx, tt.value,
(case when tt.value > grp + 2 then tt.value else cte.grp end),
tt.seqnum, 1 + lev
from cte join
tt
on tt.seqnum = cte.seqnum + 1
)
select *
from cte;
这是一个 db<>fiddle。 请注意,这添加了一个值为“4”的行,以显示前四行分为两组。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.