Mysql 获取表列中序列值的范围

Mysql 获取表列中序列值的范围,mysql,sql,window-functions,gaps-and-islands,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假设每个值都存储在单独的行中,您可以在此处使用一些间隙和孤岛技术: select case when min(val) <> max(val) then concat(min(val), '-', max(val)) else min(val) end val_range from (select va

我的列中有一个值列表。并希望查询范围。 例如,如果值为1,2,3,4,5,9,11,12,13,14,17,18,19

我想展示一下
1-5,9,11-14,17-19

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

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)
在早期版本中,可以使用相关子查询或用户变量模拟行号。第二种选择是:

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)

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

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)
在早期版本中,可以使用相关子查询或用户变量模拟行号。第二种选择是:

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)

作为对其他答案的补充:

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<8中模拟OLAP函数的短文,请访问:

编辑:

如果在这种情况下引入另一个维度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;

可以使用,请参见

作为其他答案的补充:

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<8中模拟OLAP函数的短文,请访问:

编辑:

如果在这种情况下引入另一个维度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;


可以使用,请参见

您是在列中实际存储逗号分隔的值列表,还是它们属于不同的行?您是在列中实际存储逗号分隔的值列表,还是它们属于不同的行?在尝试查询时,我发现val_range出现错误。我正在使用mysql 5.7。19@Zen:正如我提到的,这个解决方案需要MySQL 8.0。我用早期版本的替代方案更新了我的答案。@GMB我花了一段时间学习了rn-val查找组的技巧。它很有用。@Zen。我很惊讶rn的任务是在5.17.19中完成的。我认为在那个版本中,您应该使用order by的子查询,而这恰好起作用,因为该表是按顺序读取的。@GordonLinoff:当涉及单个表时,我总是不确定在使用变量之前是否需要预排序。您是否有文档指定了这一点?当我尝试您的查询时,我得到了val_range的一个错误。我正在使用mysql 5.7。19@Zen:正如我提到的,这个解决方案需要MySQL 8.0。我用早期版本的替代方案更新了我的答案。@GMB我花了一段时间学习了rn-val查找组的技巧。它很有用。@Zen。我很惊讶rn的任务是在5.17.19中完成的。我认为在那个版本中,您应该使用order by的子查询,而这恰好起作用,因为该表是按顺序读取的。@GordonLinoff:当涉及单个表时,我总是不确定在使用变量之前是否需要预排序。你有没有说明这个的文档?听起来不错,但我说不出它是否适用于我的海量数据。如果我想添加另一个筛选列,该怎么办?我不确定您所说的另一个筛选列是什么意思,您是指用作数字序列分区的列吗?@Zen,我已经扩展了示例,请参见编辑。数据集越大,传统SQL92解决方案的成本就越高。正如您所看到的,mytable在查询中被引用了4次,而这只是valin GMB:s问题中按p顺序多划分行数的问题。我试图提出一个一般性问题,也许我应该具体一点。我用pos机打印卡片。表sales有序列号、pos机号和卡号的列表。我想获得特定pos机按卡金额分组销售的序列号范围。请问另一个问题。确保包含CREATETABLE语句和insert语句以及说明问题的示例数据。Dbfiddle是一个很好的Tvat工具,听起来很简洁,但我不知道它是否适用于我的海量数据。如果我想添加另一个筛选列,该怎么办?我不确定您所说的另一个筛选列是什么意思,您是指用作数字序列分区的列吗?@Zen,我已经扩展了示例,请参见编辑。数据集越大,传统SQL92解决方案的成本就越高。正如您所看到的,mytable在查询中被引用了4次,而这只是valin GMB:s问题中按p顺序多划分行数的问题。我试图提出一个一般性问题,也许我应该具体一点。我用pos机打印卡片。表sales有序列号、pos机号和卡号的列表。我想获得特定pos机按卡金额分组销售的序列号范围。请问另一个问题。确保包含CREATETABLE语句和insert语句以及说明问题的示例数据。DBFIDLE是tvat的优秀工具