获取表列中序列值的范围

Posted

技术标签:

【中文标题】获取表列中序列值的范围【英文标题】:get the range of sequence values in table column 【发布时间】: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

【问题讨论】:

您实际上是在列中存储以逗号分隔的值列表,还是它们属于不同的行? 【参考方案1】:

假设每个值都存储在单独的行中,您可以在此处使用一些间隙和孤岛技术:

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 中可用):

Demo on DB Fiddle

| val_range | | :-------- | | 1-5 | | 9 | | 11-14 | | 17-19 |

在早期版本中,您可以使用相关子查询或用户变量来模拟 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)

【讨论】:

当我尝试您的查询时,我收到了 val_range 的错误。我正在使用 mysql 5.7.19 @Zen:正如我提到的,这个解决方案需要 MySQL 8.0。我用早期版本的替代方法更新了我的答案。 @GMB 我花了一段时间来学习rn - val 查找群组的技巧。挺好用的。 @Zen。 . .我很惊讶 rn 在 5.17.19 工作的任务。我认为在那个版本中,您应该对order by 使用子查询,这恰好可以工作,因为该表是“按顺序”读取的。 @GordonLinoff:当涉及单个表时,我总是不确定我们是否需要在使用变量之前进行预购。你有指定的文档吗?【参考方案2】:

作为其他答案的补充:

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

mysql-row_number

Fiddle

编辑:

如果引入另一个维度(在本例中为 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

【讨论】:

听起来很整洁,但我不能说它适用于我的海量数据。如果我想添加另一个过滤列怎么办。 不确定您所说的另一个过滤列是什么意思,您是指用作数字序列分区的列吗? @Zen,我已经扩展了示例,请参阅编辑。数据集越大,传统 SQL92 解决方案的成本就越高。如您所见,mytable 在查询中被引用了 4 次,而这只是 row_number() over(partition by p order by val)in GMB:s 问题的问题。 我试图提出一个一般性问题,也许我应该具体一点。我使用pos机打印卡片。表 sales 有 serial_no、pos_machine_no 和 card_amount 的列表。我想获取按 card_amount 分组的特定 pos 机器出售的 serial_no 的范围。 再问一个问题。确保包括带有说明问题的示例数据的 create table 语句和 insert 语句。 Dbfiddle 是 tvat 的绝佳工具

以上是关于获取表列中序列值的范围的主要内容,如果未能解决你的问题,请参考以下文章

如何在SQL Server表列中查找相同值的行

通过使用php将表单中的值添加到表列中的现有值来更新数据库中的值的问题

宏以获取列中每个唯一值的范围

如何从表列中获取xml值

获取 ant.design 表列中另一列的值?

如何查询从表列中选择所有输入