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を最初からやり直すときです。どうすればこれを達成できますか?また、これを行うために必要なテーブルには5,200万行あるため、かなり効率的である必要があります。

追加情報

IDは真にシーケンシャルですが、RowNumberはそうではない場合があります。RowNumberは常に1で始まると思いますが、たとえば、group1のRowNumberは「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」である可能性があります...高い番号の後に低い番号が続くと、新しいグループになります。

SQLServer2012のソリューションは次のようになります。

  1. 前の行にアクセスし、その行が新しいグループの開始であるかどうかにLAGフラグを設定するために使用します。10
  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と、この計画では1回のスキャンが行わ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 に答える