【问题标题】:Group by numbers that are in sequence按顺序的数字分组
【发布时间】:2011-09-26 01:53:06
【问题描述】:

我有一些这样的数据:

row    id
1      1
2      36
3      37
4      38
5      50
6      51

我想查询它看起来像这样:

 row    id    group
 1      1     1
 2      36    2
 3      37    2
 4      38    2
 5      50    3
 6      51    3

... 这样我就可以在数字连续的地方进行 GROUP BY。

另外,循环/游标是不可能的,因为我正在处理大量数据,谢谢。

【问题讨论】:

  • 如何确定哪些行属于特定组?
  • 从数据上看,当下一个值与上一个值连续时,同组,否则组增加

标签: sql sql-server tsql group-by


【解决方案1】:
;WITH firstrows AS
(
    SELECT id, ROW_NUMBER() OVER (ORDER BY id) groupid
    FROM Table1 a
    WHERE id - 1 NOT IN (SELECT b.id FROM Table1 b)
)
SELECT id, 
    (
        SELECT MAX(b.groupid)
        FROM firstrows b
        WHERE b.id <= a.id
    ) groupid
FROM Table1 a

【讨论】:

  • 喜欢您的解决方案!我宁愿使用lag 来查找以前的id,然后过滤掉prev is null or (id - prev) &gt; 1 的值
【解决方案2】:
with
  data(row, id) as (
    select * 
    from (
      values
       (1,1)
      ,(2,36)
      ,(3,37)
      ,(4,38)
      ,(5,50)
      ,(6,51)
    ) as foo(row, id)
  ),
  anchor(row, id) as (
    select row, id
    from data d1
    where not exists(select 0 from data d2 where d2.id = d1.id - 1)
  )
select d1.*, dense_rank() over(order by foo.id) as thegroup
from
  data d1
  cross apply (select max(id) from anchor where anchor.id <= d1.id) as foo(id)
order by
  d1.row
  ;

【讨论】:

  • Hmmm... 批量执行时,三个查询(1,2,3)可以分别占执行费用的 14%/46%/41%。这个是最便宜的;)
  • 这会给你 ID,但它是 GROUP 吗?
  • @FlyingStreudel 这给出了分组的组 ID。诀窍是计算它们,实际的后续分组是微不足道的。看看其他答案。
  • 如果它快得多,我可能最终会使用这个。我现在正在对我的数据进行尝试。
  • 有趣的是,当我用我的数据批量运行this onethis one 时,你的只占相对成本的6%。但是,这两个查询花费的时间几乎相同。你的只快了大约 10 秒,总时间大约是 1 分 40 秒。这是为什么呢?
【解决方案3】:

row 值的序列中可能存在间隙并且假设这些间隙应该被忽略的基础上,此解决方案做了更多的工作,这是绝对必要的。

设置测试数据:

DECLARE @table TABLE
(ROW INT,
id INT
)

INSERT @table
SELECT 1,1
UNION SELECT 2,36
UNION SELECT 3,37
UNION SELECT 4,38
UNION SELECT 5,50
UNION SELECT 6,51

输出查询

;WITH grpCTE
AS
(
    SELECT ROW, id,
    ROW_NUMBER() OVER (ORDER BY ROW
                        ) AS rn
    FROM @table
)
,recCTE
AS
(
    SELECT ROW, id, rn, 1 AS grp
    FROM grpCTE
    WHERE rn = 1

    UNION ALL

    SELECT g.row, g.id, g.rn, CASE WHEN g.id = r.id + 1 THEN r.grp ELSE r.grp + 1 END AS grp
    FROM grpCTE AS g
    JOIN recCTE AS r
    ON g.rn = r.rn + 1
)
SELECT row, id, grp FROM recCTE

【讨论】:

    【解决方案4】:
    create table #temp
    (
        IDUnique int Identity(1,1),
        ID int, 
        grp int
    )
    
    
    Insert into #temp(ID) Values(1)
    Insert into #temp(ID) Values(36)
    Insert into #temp(ID) Values(37)
    Insert into #temp(ID) Values(38)
    Insert into #temp(ID) Values(50)
    Insert into #temp(ID) Values(51)
    
    declare @IDUnique int
    declare @PreviousUnique int
    declare @ID int
    declare @grp int
    declare @Previous int
    declare @Row int
    
    DECLARE @getAccountID CURSOR SET @getAccountID = CURSOR FOR SELECT Row_Number() Over(Order by IDUnique) Row, IDUnique, ID  From #temp
    OPEN @getAccountID
    FETCH NEXT FROM @getAccountID INTO @Row, @IDUnique, @ID 
    WHILE @@FETCH_STATUS = 0
    BEGIN
        IF(@Row = 1)
        Begin
            update #temp set grp = 1 Where IDUnique = @IDUnique
            set @Previous = @ID
            set @grp = 1
        End
        Else If (@Previous + 1 = @ID)
        Begin
            update #temp set grp = @grp Where IDUnique = @IDUnique
            set @Previous = @ID
        End
        Else
        Begin
            set @Previous = @ID
            set @grp = @grp + 1
            update #temp set grp = @grp Where IDUnique = @IDUnique
        End
        FETCH NEXT FROM @getAccountID INTO @Row, @IDUnique, @ID
    END
    CLOSE @getAccountID
    DEALLOCATE @getAccountID
    
    Select * from #temp
    Drop Table #temp
    

    【讨论】:

    • 这个实际上是最快的。去图吧。
    • @Gagege 你说循环/游标是不可能的,所以我们没有尝试;)
    • @GSerg 我认为它会太慢。我很抱歉!这周我学到了很多关于 SQL 的知识。
    【解决方案5】:
     Select T.Id, T.Row, groupId as "Group", dr  FROM tbrows T
    Left Outer Join
        (
        Select min(id) as groupId,DENSE_RANK() over( order by min(id)) as dr, MIN(row-id) as d, Sum(1) as s FROM tbrows
             Group BY (row-id)
        ) U
    On (T.Id >= U.groupId) and (T.Id < U.groupId+U.s)
    Order By T.Id
    

    【讨论】:

    • 我修改了加入条件;它现在可以工作了,检查一下
    猜你喜欢
    • 2021-05-30
    • 2018-04-18
    • 2022-01-04
    • 1970-01-01
    • 2017-02-28
    • 2021-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多