【问题标题】:SQL Server grouping rowsSQL Server 分组行
【发布时间】:2017-06-12 20:42:36
【问题描述】:

我有这些数据:

     Id    | Name  | count |  Group_number      
     ------+-------+-------+--------------
     1     | cdd   |  50   |       0  
     2     | cdd   |  15   |       0  
     3     | cdd   |  0    |       0  
     4     | cdd   |  25   |       0   
     5     | cdd   |  11   |       0

我想要一个脚本,在条件下创建三个或四个组:Sum(count) for each group

我想要这个输出:

     1    | cdd    |  50    |      1  
     2    | cdd    |  15    |      2  
     3    | cdd    |  0     |      2  
     4    | cdd    |  25    |      2  
     5    | cdd    |  11    |      3

【问题讨论】:

  • 哪个sql数据库?
  • 数据如何分组?似乎没有任何东西可以直接将 id 与所需的输出相关联?
  • 能否请您规定组范围。 OP 不完整,如果可能,请发布原始数据
  • @ObsidianAge 看起来是按 ID 排序的增量总和。每次达到 50 时,都会添加一个新组。
  • 我知道这与求和到 50 有关。现在这更有意义了 ;)

标签: sql tsql sql-server-2014


【解决方案1】:

假设必须对每个 name 执行此操作,您可以使用递归 cte。

with rownums as (select t.*,row_number() over(partition by name order by id) as rnum from t)
,cte(rnum,id,name,cnt,runningsum,grp) as  
(select rnum,id,name,cnt,cnt,1  from rownums where rnum=1
 union all
 select t.rnum,t.id,t.name,t.cnt
 ,case when c.runningsum+t.cnt > 50 then t.cnt else c.runningsum+t.cnt end
 ,case when c.runningsum+t.cnt > 50 then t.id else c.grp end
 from cte c
 join rownums t on t.rnum=c.rnum+1 and t.name=c.name
) 
select id,cnt,name,dense_rank() over(partition by name order by grp) as grp
from cte

Sample Demo

跟踪运行总和并在超过 50 时将其重置。当总和超过 50 时,请记住 id。这可用于分配组号。

【讨论】:

    【解决方案2】:

    对于计数小于 50 的记录,我们可以通过计算计数的运行总计然后将该运行总计除以 50 来简单地生成分组 ID。但是,由于某些记录可能已经具有大于或等于 50 可能会生成不正确的 ID。为了解决这个问题,我们需要以某种方式强制在下一条记录上生成新的分组 ID。如果当前记录计数为 50 或更大,则只需将下一条记录的计数调整 50 即可完成此操作。 以下示例演示了如何做到这一点:

    CREATE TABLE #Items
    (
         [Id]       INT NOT NULL PRIMARY KEY
        ,[Name]     VARCHAR(50) NOT NULL
        ,[Count]    INT NOT NULL
    )
    
    INSERT INTO #Items
    VALUES 
    (1, 'cdd', 50 ),         
    (2, 'cdd', 15 ),       
    (3, 'cdd', 0  ),        
    (4, 'cdd', 25 ),         
    (5, 'cdd', 11 );       
    
    ;WITH CTE_ItemCountsAdjusted
    AS
    (
        SELECT   [Id]       
                ,[Name] 
                ,[Count]
                ,LAG([Count], 1, 0) OVER (PARTITION BY [Name] ORDER BY [Id]) AS PrevCount
                ,(
                    CASE 
                        WHEN LAG([Count], 1, 0) OVER (PARTITION BY [Name] ORDER BY [Id]) >= 50 THEN [Count] + 50
                        ELSE [Count]
                    END
                ) AdjustedCount
        FROM    #Items
    )
    SELECT   [Id]       
            ,[Name] 
            ,[Count]
            ,SUM([AdjustedCount]) OVER (PARTITION BY [Name] ORDER BY [Id] ROWS UNBOUNDED PRECEDING) / 50 AS [Group_number]
    FROM    CTE_ItemCountsAdjusted
    ORDER BY    [Id]   
    

    这种方法消除了递归调用的需要。请注意,如果您需要组 id 严格按顺序排列(组号之间没有间隙),那么您可以使用 DENSE_RANK() 窗口函数来实现此目的,如下例所示:

    INSERT INTO #Items
    VALUES 
    (1, 'cdd', 50 ),         
    (2, 'cdd', 15 ),       
    (3, 'cdd', 0  ),        
    (4, 'cdd', 25 ),         
    (5, 'cdd', 11 ),      
    (6, 'cdd', 200 ),
    (7, 'cdd', 10 );  
    
    ;WITH CTE_ItemCountsAdjusted
    AS
    (
        SELECT   [Id]       
                ,[Name] 
                ,[Count]
                ,LAG([Count], 1, 0) OVER (PARTITION BY [Name] ORDER BY [Id]) AS PrevCount
                ,(
                    CASE 
                        WHEN LAG([Count], 1, 0) OVER (PARTITION BY [Name] ORDER BY [Id]) >= 50 THEN [Count] + 50
                        ELSE [Count]
                    END
                ) AdjustedCount
        FROM    #Items
    
    ),CTE_ItemCountsWithGroupID
    AS
    (
        SELECT   [Id]       
                ,[Name] 
                ,[Count]
                ,SUM([AdjustedCount]) OVER (PARTITION BY [Name] ORDER BY [Id] ROWS UNBOUNDED PRECEDING) / 50 AS [Group_number]
        FROM    CTE_ItemCountsAdjusted  
    )
    SELECT   [Id]       
            ,[Name] 
            ,[Count]
            ,[Group_number]
    

    【讨论】:

      猜你喜欢
      • 2020-12-28
      • 2021-12-08
      • 2017-02-03
      • 1970-01-01
      • 2016-01-11
      • 1970-01-01
      • 2015-09-29
      • 2017-11-10
      • 2017-01-17
      相关资源
      最近更新 更多