2013-02-15 30 views
7

Tôi có bảng với một cái gì đó dữ liệu như thế này:Kết quả Nhóm SQL dựa trên thứ tự

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 

Tôi muốn nhóm mỗi bộ RowNumbers Vì vậy mà kết quả của tôi là một cái gì đó như thế này:

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 

Các cách duy nhất tôi biết nơi mỗi nhóm bắt đầu và dừng lại là khi RowNumber bắt đầu lại. Làm thế nào tôi có thể thực hiện điều này? Nó cũng cần phải được khá hiệu quả kể từ khi bảng tôi cần phải làm điều này trên có 52 Triệu Rows.

Thông tin bổ sung

ID là thực sự liên tục, nhưng RowNumber có thể không. Tôi nghĩ RowNumber sẽ luôn bắt đầu bằng 1 nhưng ví dụ RowNumbers cho nhóm1 có thể là "1,1,2,2,3,4" và đối với nhóm2, chúng có thể là "1,2,4,6", v.v.

+2

Nhóm thứ 27 nên nhận được gì (sau 'z')? –

+0

Bạn đang cố gắng tìm gì từ truy vấn? –

+0

@ypercube nó không quan trọng chỉ cần miễn là số duy nhất của nó ... thay vì chữ cái sẽ được sử dụng tốt. – matthew

Trả lời

6

đối với các yêu cầu làm rõ trong các ý kiến ​​

các rownumbers cho nhóm1 có thể là "1,1,2,2,3,4" và cho nhóm2 họ có thể là "1,2,4,6" ... số cao hơn theo sau là số thấp hơn sẽ là nhóm mới.

Giải pháp SQL Server 2012 có thể như sau.

  1. Sử dụng LAG để truy cập hàng trước và thiết lập một lá cờ để 1 nếu hàng đó là sự bắt đầu của một nhóm mới hoặc 0 khác.
  2. Tính tổng chạy của các cờ này để sử dụng làm giá trị nhóm.

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

Giả sử ID là clustered index phương án này có một quét chống YourTable và tránh bất kỳ hoạt động phân loại.

Plan

+0

Tôi nghĩ RowNumber sẽ luôn bắt đầu bằng 1, nhưng nó có thể không thực sự tuần tự. Ví dụ. các nhóm cho nhóm 1 có thể là "1,1,2,2,3,4" và đối với nhóm 2 chúng có thể là "1,2,4,6" – matthew

+0

@matthew - Vậy điều gì biểu thị một nhóm mới? Số cao hơn theo sau là số thấp hơn? Bạn đang sử dụng phiên bản SQL Server nào? –

+0

Đúng, số cao hơn theo sau là số thấp hơn sẽ là một nhóm mới. – matthew

2

Nếu id là thực sự liên tục, bạn có thể làm:

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

Điều này có vẻ đầy hứa hẹn. Id thực sự là tuần tự, nhưng RowNumber có thể không. Ví dụ. nhóm 1 có thể bằng "1,1,2,2,3,4" và nhóm 2 có thể là "1,2,4,6" – matthew

+0

@matthew - Nếu 'id' là cột 'IDENTITY' thì" thực sự tuần tự "không phải là được bảo đảm. –

+0

@MartinSmith Tôi biết. Tôi đang thêm nó vào hồ sơ, vì vậy tôi có thể đảm bảo rằng nó thực sự là. – matthew

1

Ngoài ra bạn có thể sử dụng đệ quy 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 

Demo trên SQLFiddle

1

Làm thế nào về:

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 

Điều này sẽ hoạt động trên SQL 2005. Bạn cũng có thể sử dụng xếp hạng() thay thế nếu bạn không quan tâm đến các số liên tiếp.

Các vấn đề liên quan