【问题标题】:Create range of ID without cursor创建不带光标的 ID 范围
【发布时间】:2018-12-10 04:48:29
【问题描述】:

不确定是否已经问过这个或类似的问题,但我找不到。

在不更改值的情况下创建 ID 范围的要求。可以使用此架构:

declare @mytable as table(ID int, Val int)

insert into @mytable values
(1,     1),
(2,     1),
(3,     1),
(4,     2),
(5,     2),
(6,     2),
(7,     2),
(8,     1),
(9,     1),
(10,    1),
(11,    4),
(12,    4),
(13,    4),
(14,    4),
(15,    4),
(16,    5);

预期的结果是

StartID     EndID   Val
1           3       1
4           7       2
8           10      1
11          15      4
16          16      5

现在我可以通过运行 cursor 来实现这一点,如果 n 情况下记录的数量将是数百万,我认为 cursor 会更慢。我希望它可以使用一些复合查询来编写,但无法弄清楚如何。

所以我在编写这种查询时需要帮助,而且不用说,它不是学校/拼贴项目/作业。

【问题讨论】:

  • 奇怪!!投反对票,不评论这里出了什么问题?
  • 您使用的是哪个版本的 SQL Server? (2005 / 2016 / 等)
  • 是SQL server 2017 express

标签: sql sql-server tsql gaps-and-islands sql-server-2017


【解决方案1】:

这是一个 场景,您尝试根据Val 中的更改将记录分组在一起。

这是使用window functions 来确定@​​987654324@ 何时更改,并分配island_nbr

答案:

select min(b.ID) as StartID
, max(b.ID) as EndID
, max(b.Val) as Val
from (
    select a.ID
    , a.Val
    , sum(a.is_chng_flg) over (order by a.ID asc) as island_nbr
    from (
        select m.ID
        , m.Val
        , case lag(m.Val, 1, m.Val) over (order by m.ID asc) when m.Val then 0 else 1 end is_chng_flg
        from @mytable as m
        ) as a
    ) as b
group by b.island_nbr --forces the right records to show up
order by 1

【讨论】:

  • 这正是我所需要的……谢谢
  • 此查询使用的最低/最旧 SQL Server 版本是什么?
  • 我相信那会是 SQL Server 2012。
【解决方案2】:

这是一个孤岛问题。但最简单的方法是行号的不同:

select min(id) as startId, max(id) as endId, val
from (select t.*,
             row_number() over (order by id) as seqnum,
             row_number() over (partition by val order by id) as seqnum_v
      from @mytable t
     ) t
group by (seqnum - seqnum_v), val
order by startId;

【讨论】:

  • 没有注意到这是一个更简单的解决方案,当另一个解决方案由于其他问题(数据问题)而失败时,我意识到较小的查询更容易调试/修复:)
猜你喜欢
  • 2014-07-01
  • 2013-05-24
  • 2012-07-05
  • 2015-06-27
  • 1970-01-01
  • 2019-06-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多