SQL查询将连续范围的数字分组到不同的分组集中

Posted

技术标签:

【中文标题】SQL查询将连续范围的数字分组到不同的分组集中【英文标题】:SQL Query to group continuous range of numbers into different grouping sets 【发布时间】:2013-01-22 12:43:10 【问题描述】:

我有一张包含大约一百万条记录的表。下面给出了几个示例值:

Group    MemberNo
ABC           100
ABC           101
ABC           200
ABC           201
ABC           202
ABC           203
XYZ           100
XYZ           101
ABC           204
XYZ           301
XYZ           302
ABC           500
ABC           600

我希望将具有相同组的连续值范围分组为这样的集合:

Group  FromMemberNo      ToMemberNo
ABC             100             101
ABC             200             204
XYZ             100             101
XYZ             301             302
ABC             500             500
ABC             600             600

请从上表中看到,由于 100 和 101 是连续的,因此它已被分组为一条记录 ABC 100 到 101。我已经尝试过 this 线程并且对我来说工作正常。但这比预期花费的时间要长。 请帮助我实现这一目标。

提前致谢。

【问题讨论】:

在您链接的问题中接受的答案可能是最有效的方法。需要多长时间?您预计需要多长时间?执行计划是什么样的?你有Group,MemberNo 的索引吗? 嗨@MartinSmith,还有4 列,为简单起见,我只添加了1 列。我对所有这些列都有索引,但查询仍然需要 4 到 5 秒。 您每次都需要处理百万行吗? 嗨@HamletHakobyan,我打算在不触及我的应用程序逻辑的情况下将其作为数据层中的视图来实现。您是真的,不需要每次都处理所有行。 请发布您的实际表结构以及索引、您正在运行的查询和执行计划,我们可以查看您是否缺少任何可以避免排序的索引。 【参考方案1】:

另一种解决方案。我可以了解性能,但似乎可以完成工作(仅限 sql 2012)

declare @t table (g varchar(3), mn int)

insert into @t values 
('ABC',           100),
('ABC',           101),
('ABC',           200),
('ABC',           201),
('ABC',           202),
('ABC',           203),
('XYZ',           100),
('XYZ',           101),
('ABC',           204),
('XYZ',           301),
('XYZ',           302),
('ABC',           500),
('ABC',           600),
('XYZ',           400);


with ctet as (
    select 
        row_number() over (order by g, mn) rn,
        *, 
        case when lag(mn, 1) over (order by g, mn) <> mn - 1 then 1 else 0 end as d 
    from 
        @t
)

select g, min(mn), max(mn)
from
    (
    select 
        *,
        (select sum(d) from ctet vv where vv.rn <= ctet.rn) s
    from 
        ctet
    ) v
group by g, s

我很确定存在滞后或领先的更智能解决方案,但我找不到。

===== 编辑 =====

终于也适用于 2005 年

 with ctet as (
    select 
        row_number() over (order by t.g, t.mn) rn,
        t.*, 
        case when tt.g is null then 1 else 0 end as d
    from 
        @t t
        left join @t tt on t.g = tt.g and t.mn = tt.mn + 1
)

【讨论】:

谢谢,但@Andriy M 的解决方案只需要一点时间!

以上是关于SQL查询将连续范围的数字分组到不同的分组集中的主要内容,如果未能解决你的问题,请参考以下文章

Oracle SQL 查询对连续记录进行分组

按连续日期分组,忽略 SQL 中的周末

如何按范围分组,或有条件地从查询结果中选择

SQL Server - 在按特定列分组时构建动态范围的数字

使用 T-SQL 将 OHLC-Stockmarket 数据分组到多个时间范围内

Oracle sql查询按日期对连续记录进行分组