【发布时间】:2020-08-28 12:39:53
【问题描述】:
我的专栏中有一个价值列表。并想查询范围。 例如。如果值为 1,2,3,4,5,9,11,12,13,14,17,18,19
我想显示 1-5,9,11-14,17-19
【问题讨论】:
-
您实际上是在列中存储以逗号分隔的值列表,还是它们属于不同的行?
标签: mysql sql window-functions gaps-and-islands
我的专栏中有一个价值列表。并想查询范围。 例如。如果值为 1,2,3,4,5,9,11,12,13,14,17,18,19
我想显示 1-5,9,11-14,17-19
【问题讨论】:
标签: mysql sql window-functions gaps-and-islands
假设每个值都存储在单独的行中,您可以在此处使用一些间隙和孤岛技术:
select case when min(val) <> max(val)
then concat(min(val), '-', max(val))
else min(val)
end val_range
from (select val, row_number() over(order by val) rn from mytable) t
group by val - rn
order by min(val)
这个想法是通过获取值和递增排名之间的差值来构建连续值组,递增排名是使用row_number() 计算的(在 MySQL 8.0 中可用):
在早期版本中,您可以使用相关子查询或用户变量来模拟 row_number()。第二个选项如下:
select case when min(val) <> max(val)
then concat(min(val), '-', max(val))
else min(val)
end val_range
from (select @rn := 0) x
cross join (
select val, @rn := @rn + 1 rn
from (select val from mytable order by val) t
) t
group by val - rn
order by min(val)
【讨论】:
rn - val 查找群组的技巧。挺好用的。
rn 在 5.17.19 工作的任务。我认为在那个版本中,您应该对order by 使用子查询,这恰好可以工作,因为该表是“按顺序”读取的。
作为其他答案的补充:
select dn.val as dnval, min(up.val) as upval
from mytable up
join mytable dn
on dn.val <= up.val
where not exists (select 1 from mytable a where a.val = up.val + 1)
and not exists (select 1 from mytable b where b.val = dn.val - 1)
group by dn.val
order by dn.val;
1 5
9 9
11 14
17 19
不用说,但使用像 @GNB 这样的 OLAP 函数,效率要高几个数量级。
关于如何在 MySQL
编辑:
如果引入另一个维度(在本例中为 p),类似于:
select dn.p, dn.val as dnval, min(up.val) as upval
from mytable up
join mytable dn
on dn.val <= up.val
and dn.p = up.p
where not exists (select 1 from mytable a where a.val = up.val + 1 and a.p = up.p)
and not exists (select 1 from mytable b where b.val = dn.val - 1 and b.p = dn.p)
group by dn.p, dn.val
order by dn.p, dn.val;
可以使用,见Fiddle2
【讨论】:
row_number() over(partition by p order by val)in GMB:s 问题的问题。