运行长度或连续相同值编码的 SQL 查询

Posted

技术标签:

【中文标题】运行长度或连续相同值编码的 SQL 查询【英文标题】:SQL query for run-length, or consecutive identical value encoding 【发布时间】:2015-06-14 13:45:11 【问题描述】:

我的目标是获取一组按id 排序的数据,并返回一个结果集,该结果集指示val 列相同的连续行数。例如。鉴于此数据:

| id | val |
|  1 |  33 |
|  2 |  33 |
|  3 |  44 |
|  4 |  28 |
|  5 |  44 |
|  6 |  44 |

我想看看这个结果:

| id | val | run_length |
| 1  | 33  | 2          |
| 3  | 44  | 1          |
| 4  | 28  | 1          |
| 5  | 44  | 2          |

结果集中的 id 列是可选的。事实上,如果它显着增加难度,那么只需将该列排除在结果之外。我有点喜欢拥有它,因为它将结果集“固定”到表中的特定位置。

我主要对免费数据库引擎的结果感兴趣。我对解决方案的偏好顺序是:

    SQLite Postgres mysql 甲骨文 SQL 服务器 Sybase

【问题讨论】:

【参考方案1】:

我将在您的列表中选择 #2,因为在 SQLite 中使用单个查询执行此操作非常痛苦。以下是标准SQL:

select min(id), val, count(*) as runlength
from (select t.*,
             (row_number() over (order by id) -
              row_number() over (partition by val order by id)
             ) as grp
      from data t
     ) t
group by grp, val;

这使用两个行号计算的差异来识别相同值的序列。它应该可以在数据库 2、4、5 和 6 的最新版本中运行。

【讨论】:

来自未来的注释 - 从 3.25.0 (2018-09-15) 开始,这在 SQLite 中现在确实有效。 cfsqlite.org/windowfunctions.html【参考方案2】:

我一直在 SQLITE 的 RLE 空间中四处游荡,偶然发现了这篇文章。我相信这段代码适用于#1。第一个答案是正确的,这在 SQLite 中作为单个查询有点痛苦。

create table example (id integer primary key autoincrement, val integer);

insert into example (val) values (33);
insert into example (val) values (33);
insert into example (val) values (44);
insert into example (val) values (28);
insert into example (val) values (44);
insert into example (val) values (44);


select ren.low_id, e2.val, (ren.high_id - ren.low_id)+1
from example e2
inner join (
select min(hb.low_id) as low_id, hb.high_id as high_id
from 
(
    with nexample(low_id, high_id, val) 
    as 
    (
    select e.id, e.id, e.val from example e
    union all
    select ne.low_id, eu.id, ne.val 
    from nexample ne
    inner join example eu on eu.id = ne.high_id+1 AND eu.val=ne.val
    )
    select ne.low_id, max(ne.high_id) as high_id from nexample ne
    group by ne.low_id
) hb
group by hb.high_id
) ren on ren.low_id = e2.id;

输出:

1|33|2
3|44|1
4|28|1
5|44|2

请注意,此解决方案在非常稀疏的集合上表现不佳...我正在寻找一种替代方法来处理稀疏集合。

例如,在一组 10000 行中,val 集为 [0,1],但所有值均为 0。此代码在我的硬件上运行大约需要 2 分钟 30 秒。不太好。

【讨论】:

以上是关于运行长度或连续相同值编码的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

SQL:计算每个设备集连续出现相同值的所有记录并返回最高计数

sql - 当我得到 2 个或更多具有相同值的值时,仅更新 1 个(查询找到的第一个)值的方法?

如果另一列有重复值,sql查询用相同的值替换列

查找具有已定义结束的连续相同值的行组 (SQL Redshift)

SQL:计算每个设备集连续出现相同值的所有记录并返回最高计数:百分比

如何在 PL/SQL 中使用循环多次运行相同的查询?