7

我有这样的数据表:

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

4 回答 4

6

对于评论中的明确要求

group1 的行号可以是“1,1,2,2,3,4”,而 group2 的行号可以是“1,2,4,6”......一个较大的数字后跟一个较小的数字将是一个新组。

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

  1. 用于LAG访问前一行并设置一个标志,1如果该行是新组的开始或0其他。
  2. 计算这些标志的运行总和以用作分组值。

代码

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小提琴

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

计划

于 2013-02-15T20:21:43.687 回答
2

如果 id 确实是连续的,您可以执行以下操作:

select t.*,
       (id - rowNumber) as grp
from t
于 2013-02-15T20:25:11.780 回答
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上的演示

于 2013-02-15T22:24:11.313 回答
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() 代替。

于 2013-02-15T22:43:28.207 回答