連続する値のシーケンス番号を計算する必要があります。 ROW_NUMBER()
の仕事のようですね。
_DECLARE @Data TABLE
(
Sequence TINYINT NOT NULL PRIMARY KEY,
Subset CHAR(1) NOT NULL
)
INSERT INTO @Data (Sequence, Subset) VALUES
(1, 'A'),
(2, 'A'),
(3, 'A'),
(4, 'B'), -- New subset
(5, 'B'),
(6, 'A') -- New subset
SELECT
Sequence, Subset,
ROW_NUMBER() OVER (PARTITION BY Subset ORDER BY Sequence) AS SeqWithinGroup
FROM
@Data
_
PARTITION
句がSubset
の変更ごとにカウントをリセットすることを期待していましたが、代わりにSQL Serverは指定されたSubset
値のすべての値を収集し、それらに番号を付けます。ここに私が期待したものと私が得たものがあります:
_Sequence Subset Expected Actual
-------- ------ -------- -----
1 A 1 1
2 A 2 2
3 A 3 3
4 B 1 1
5 B 2 2
6 A *1* *4*
_
SQLが行#6に達すると、サブセット「A」の番号付けを再開しますが、たまたま「A」という名前が付けられた新しいサブセットの最初の行と見なします。
デフォルトの動作ではなく、厳密にROW_NUMBER()
パーティションを作成する方法はありますか?
SQLで連続した値を数えることに関して、ここや他の場所で多くの質問があります。ただし、_PARTITION BY
_フィールドの繰り返し値に対処するものはまだ見ていません。ほとんどは値の増加のみを扱い、多くの場合日付を扱います。
私はLAG()
を使用してこれに対処できました:
_SELECT
Sequence, Subset,
CASE WHEN Sequence = 1 OR Subset <> LAG(Subset, 1) OVER (ORDER BY Sequence)
THEN 'New subset'
ELSE 'Continuation'
END
FROM
@Data
_
これは、レコード#1、#4、および#6の「新しいサブセット」を返します。どうやらLAG()
パーティションはROW_NUMBER()
とは少し異なります。
明らかにこれは行番号を提供しませんが、サブセット識別子が繰り返される場合に、連続した番号のシーケンスを識別するという目標を達成するのに役立ちました。
私は この投稿 からの私の回答を使用して、問題に合わせて修正しました。
--Demo setup
;DECLARE @Data TABLE
(
Sequence TINYINT NOT NULL PRIMARY KEY,
Subset CHAR(1) NOT NULL
)
;INSERT INTO @Data (Sequence, Subset) VALUES
(1, 'A'),
(2, 'A'),
(3, 'A'),
(4, 'B'), -- New subset
(5, 'B'),
(6, 'A') -- New subset
--The solution
--Create a grouping for consecutive values called grp
;WITH _cte
AS (
SELECT *
,DATEADD(DAY, - ROW_NUMBER() OVER (
PARTITION BY Subset ORDER BY [Sequence]
), [Sequence]) AS grp
FROM @Data
)
,AddedRn --add a row number for each entry in the group
AS (
SELECT *
,ROW_NUMBER() OVER (
PARTITION BY grp ORDER BY sequence
) AS rn
FROM _cte
)
--Select result ordering by Sequence
SELECT Sequence, Subset, grp, rn as SeqWithinGroup
FROM AddedRn
order by Sequence
| Sequence | Subset | grp | SeqWithinGroup |
|----------|--------|-------------------------|----------------|
| 1 | A | 1900-01-01 00:00:00.000 | 1 |
| 2 | A | 1900-01-01 00:00:00.000 | 2 |
| 3 | A | 1900-01-01 00:00:00.000 | 3 |
| 4 | B | 1900-01-04 00:00:00.000 | 1 |
| 5 | B | 1900-01-04 00:00:00.000 | 2 |
| 6 | A | 1900-01-03 00:00:00.000 | 1 |
ここで行うことは、
rst
)sum()
はグループを取得します(コードの列grp
)row_number()
を取得します。コード、
SELECT row_number() OVER (PARTITION BY grp ORDER BY sequence) AS number,
sequence,
subset
FROM (
SELECT count(rst) OVER (ORDER BY sequence) AS grp, *
FROM (
SELECT CASE WHEN subset != lag(subset) OVER (ORDER BY sequence) THEN 1 END AS rst, *
FROM foo
) AS t1
) AS t2;
DBFiddleとその結果をここで確認できます