根据订单对SQL结果进行分组

时间:2013-02-15 20:15:06

标签: sql sql-server tsql sql-server-2005 sql-server-2012

我的表格数据如下:

ID     | RowNumber     | Data
------------------------------
1      | 1             | Data
2      | 2             | Data
3      | 3             | Data
4      | 1             | Data
5      | 2             | Data
6      | 1             | Data
7      | 2             | Data
8      | 3             | Data
9      | 4             | Data

我想对每组RowNumbers进行分组,以便我的结果是这样的:

ID     | RowNumber     | Group | Data
--------------------------------------
1      | 1             | a     | Data
2      | 2             | a     | Data
3      | 3             | a     | Data
4      | 1             | b     | Data
5      | 2             | b     | Data
6      | 1             | c     | Data
7      | 2             | c     | Data
8      | 3             | c     | Data
9      | 4             | c     | Data

我知道每个组开始和停止的唯一方法是RowNumber重新开始。我怎么能做到这一点?它还需要相当高效,因为我需要这样做的表有5200万行。

其他信息

ID确实是顺序的,但RowNumber可能不是。我认为RowNumber总是以1开头,但例如group1的RowNumbers可以是“1,1,2,2,3,4”,而group2则可以是“1,2,4,6”等。

4 个答案:

答案 0 :(得分:6)

对于评论中澄清的要求

  

group1的rownumbers可能是“1,1,2,2,3,4”,而group2则是   可能是“1,2,4,6”......较高的数字后跟较低的数字将是a   新组。

SQL Server 2012解决方案可能如下所示。

  1. 使用LAG访问上一行,如果该行是新组的开头,则设置为1的标记,否则设置为0
  2. 计算这些标志的运行总和以用作分组值。
  3. <强>代码

    WITH T1 AS
    (
    SELECT *,
           LAG(RowNumber) OVER (ORDER BY ID) AS PrevRowNumber
    FROM YourTable
    ), T2 AS
    (
    SELECT *,
           IIF(PrevRowNumber IS NULL OR PrevRowNumber > RowNumber, 1, 0) AS NewGroup
    FROM T1
    )
    SELECT ID,
            RowNumber,
            Data,
            SUM(NewGroup) OVER (ORDER BY ID 
                                ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS  Grp
    FROM T2
    

    SQL Fiddle

    假设ID是聚集索引,则此计划对YourTable进行一次扫描,并避免任何排序操作。

    Plan

答案 1 :(得分:2)

如果id是真正的顺序,你可以这样做:

select t.*,
       (id - rowNumber) as grp
from t

答案 2 :(得分:1)

您也可以使用递归CTE

 ;WITH cte AS
 (       
  SELECT ID, RowNumber, Data, 1 AS [Group]
  FROM dbo.test1
  WHERE ID = 1
  UNION ALL
  SELECT t.ID, t.RowNumber, t.Data, 
         CASE WHEN t.RowNumber != 1 THEN c.[Group] ELSE c.[Group] + 1 END
  FROM dbo.test1 t JOIN cte c ON t.ID = c.ID + 1
  )
  SELECT *
  FROM cte

SQLFiddle上的演示

答案 3 :(得分:1)

怎么样:

select ID, RowNumber, Data, dense_rank() over (order by grp) as Grp
from (
     select *, (select min(ID) from [Your Table] where ID > t.ID and RowNumber = 1) as grp
     from [Your Table] t
) t
order by ID

这应该适用于SQL 2005.如果您不关心连续数字,也可以使用rank()。