MS SQL 不循环设置组 ID
MS SQL Set Group ID Without Looping
我想在 MS-SQL 中创建一个查询来创建一个包含递增组号的列。
这就是我希望我的数据的方式 return:
Column 1 | Column 2 | Column 3
------------------------------
I | 1 | 1
O | 2 | 2
O | 2 | 3
I | 3 | 4
O | 4 | 5
O | 4 | 6
O | 4 | 7
O | 4 | 8
I | 5 | 9
O | 6 | 10
Column 1
是 I
和 O
的意思。
Column 2
是行组(这应该在 Column 1
更改时递增)。
Column 3
是行号。
那么我如何编写查询,以便 Column 2
每次 Column 1
变化时递增?
首先,要执行此类操作,您需要一些可以标识行顺序的列。如果你有一个确定这个顺序的列,例如一个标识列,它可以用来做这样的事情:
可运行示例:
CREATE TABLE #Groups
(
id INT IDENTITY(1, 1) , -- added identity to provide order
Column1 VARCHAR(1)
)
INSERT INTO #Groups
( Column1 )
VALUES ( 'I' ),
( 'O' ),
( 'O' ),
( 'I' ),
( 'O' ),
( 'O' ),
( 'O' ),
( 'O' ),
( 'I' ),
( 'O' );
;
WITH cte
AS ( SELECT id ,
Column1 ,
1 AS Column2
FROM #Groups
WHERE id = 1
UNION ALL
SELECT g.id ,
g.Column1 ,
CASE WHEN g.Column1 = cte.Column1 THEN cte.Column2
ELSE cte.Column2 + 1
END AS Column2
FROM #Groups g
INNER JOIN cte ON cte.id + 1 = g.id
)
SELECT *
FROM cte
OPTION (MAXRECURSION 0) -- required to allow for more than 100 recursions
DROP TABLE #Groups
此代码有效地遍历记录,将每一行与下一行进行比较,如果 Column1
中的值发生变化,则递增 Column2
的值。
如果您没有标识列,那么您可以考虑添加一个。
信用@AeroX:
对于 30K 条记录,最后一行:OPTION (MAXRECURSION 0)
需要在使用 Common Table Expression (CTE) 时覆盖默认的 100 次递归。设置为0
,表示不受限制。
如果您有 sqlserver 2012+
,这将有效
DECLARE @t table(col1 char(1), col3 int identity(1,1))
INSERT @t values
('I'), ('O'), ('O'), ('I'), ('O'), ('O'), ('O'), ('O'), ('I'), ('O')
;WITH CTE AS
(
SELECT
case when lag(col1) over (order by col3) = col1
then 0 else 1 end increase,
col1,
col3
FROM @t
)
SELECT
col1,
sum(increase) over (order by col3) col2,
col3
FROM CTE
结果:
col1 col2 col3
I 1 1
O 2 2
O 2 3
I 3 4
O 4 5
O 4 6
O 4 7
O 4 8
I 5 9
O 6 10
我想在 MS-SQL 中创建一个查询来创建一个包含递增组号的列。
这就是我希望我的数据的方式 return:
Column 1 | Column 2 | Column 3
------------------------------
I | 1 | 1
O | 2 | 2
O | 2 | 3
I | 3 | 4
O | 4 | 5
O | 4 | 6
O | 4 | 7
O | 4 | 8
I | 5 | 9
O | 6 | 10
Column 1
是I
和O
的意思。Column 2
是行组(这应该在Column 1
更改时递增)。Column 3
是行号。
那么我如何编写查询,以便 Column 2
每次 Column 1
变化时递增?
首先,要执行此类操作,您需要一些可以标识行顺序的列。如果你有一个确定这个顺序的列,例如一个标识列,它可以用来做这样的事情:
可运行示例:
CREATE TABLE #Groups
(
id INT IDENTITY(1, 1) , -- added identity to provide order
Column1 VARCHAR(1)
)
INSERT INTO #Groups
( Column1 )
VALUES ( 'I' ),
( 'O' ),
( 'O' ),
( 'I' ),
( 'O' ),
( 'O' ),
( 'O' ),
( 'O' ),
( 'I' ),
( 'O' );
;
WITH cte
AS ( SELECT id ,
Column1 ,
1 AS Column2
FROM #Groups
WHERE id = 1
UNION ALL
SELECT g.id ,
g.Column1 ,
CASE WHEN g.Column1 = cte.Column1 THEN cte.Column2
ELSE cte.Column2 + 1
END AS Column2
FROM #Groups g
INNER JOIN cte ON cte.id + 1 = g.id
)
SELECT *
FROM cte
OPTION (MAXRECURSION 0) -- required to allow for more than 100 recursions
DROP TABLE #Groups
此代码有效地遍历记录,将每一行与下一行进行比较,如果 Column1
中的值发生变化,则递增 Column2
的值。
如果您没有标识列,那么您可以考虑添加一个。
信用@AeroX:
对于 30K 条记录,最后一行:OPTION (MAXRECURSION 0)
需要在使用 Common Table Expression (CTE) 时覆盖默认的 100 次递归。设置为0
,表示不受限制。
如果您有 sqlserver 2012+
,这将有效DECLARE @t table(col1 char(1), col3 int identity(1,1))
INSERT @t values
('I'), ('O'), ('O'), ('I'), ('O'), ('O'), ('O'), ('O'), ('I'), ('O')
;WITH CTE AS
(
SELECT
case when lag(col1) over (order by col3) = col1
then 0 else 1 end increase,
col1,
col3
FROM @t
)
SELECT
col1,
sum(increase) over (order by col3) col2,
col3
FROM CTE
结果:
col1 col2 col3
I 1 1
O 2 2
O 2 3
I 3 4
O 4 5
O 4 6
O 4 7
O 4 8
I 5 9
O 6 10