删除 SQL 中的光标
Removal of Cursor in SQL
一直不鼓励使用游标,游标已在我们当前的存储过程中广泛使用,并用基于集合的查询代替它们。但是这个特殊的场景是一个,我没有得到使用基于集合的查询的解决方案并被迫继续使用游标。我在下面提供了代表场景的示例代码:
DECLARE @temp varchar(10), @continuechar varchar(10)
DECLARE @table1 table (col1 varchar(10))
insert into @table1
select 'A' UNION
select 'B' UNION
select 'C' UNION
select 'D' UNION
select 'E' UNION
select 'F' UNION
select 'G'
DECLARE Cursor1 CURSOR for select Col1 from @table1
open Cursor1
FETCH NEXT from Cursor1 into @temp
WHILE @@FETCH_STATUS = 0
BEGIN
if @temp='A'
BEGIN
set @continuechar=@temp
END
if @temp='C'
BEGIN
set @continuechar=@temp
END
select @continuechar, @temp
FETCH NEXT from Cursor1 into @temp
END
CLOSE cursor1;
deallocate cursor1
在上面的示例代码中,@continuechar 变量未设置,每次执行游标时。如果 @continuechar 正在设置,则以下 select 语句将提供具有 @continuechar 当前值的结果集:
select @continuechar, @temp
如果未设置,则使用先前设置的值来提供结果集。
我们可以设置基于查询来从这种情况下删除游标吗?
首先我会添加一些 id
列以获得稳定的排序。然后简单地使用窗口函数:
SUM() OVER()
计算组数
FIRST_VALUE() OVER()
跨组传播第一个值
(来自SQL Server 2012,如有必要,您可以将其与MAX(continuechar) OVER(PARTITION BY grp)
交换)
DECLARE @table1 table (id INT IDENTITY(1,1), col1 varchar(10))
insert into @table1
select 'A' UNION
select 'B' UNION
select 'C' UNION
select 'D' UNION
select 'E' UNION
select 'F' UNION
select 'G';
WITH cte AS (
SELECT id
,col1
,CASE WHEN col1 IN('A', 'C') THEN col1 END AS continuechar
,SUM(CASE WHEN col1 IN ('A', 'C') THEN 1 ELSE 0 END)
OVER(ORDER BY id) AS grp
FROM @table1
)
SELECT id, col1,
FIRST_VALUE(continuechar) OVER(PARTITION BY grp ORDER BY id) AS continuechar
FROM cte
ORDER BY id;
编辑:
Quirky update
这仅用于纯演示。不要在生产系统上使用此方法:
DECLARE @table1 table (id INT IDENTITY(1,1) PRIMARY KEY, col1 varchar(10),
continue_char VARCHAR(10));
DECLARE @temp VARCHAR(10);
insert into @table1(col1)
select 'A' UNION
select 'B' UNION
select 'C' UNION
select 'D' UNION
select 'E' UNION
select 'F' UNION
select 'G';
UPDATE @table1
SET @temp = CASE WHEN col1 IN ('A','C') THEN col1 ELSE @temp END
,continue_char = @temp
OPTION(MAXDOP 1);
SELECT *
FROM @table1;
一直不鼓励使用游标,游标已在我们当前的存储过程中广泛使用,并用基于集合的查询代替它们。但是这个特殊的场景是一个,我没有得到使用基于集合的查询的解决方案并被迫继续使用游标。我在下面提供了代表场景的示例代码:
DECLARE @temp varchar(10), @continuechar varchar(10)
DECLARE @table1 table (col1 varchar(10))
insert into @table1
select 'A' UNION
select 'B' UNION
select 'C' UNION
select 'D' UNION
select 'E' UNION
select 'F' UNION
select 'G'
DECLARE Cursor1 CURSOR for select Col1 from @table1
open Cursor1
FETCH NEXT from Cursor1 into @temp
WHILE @@FETCH_STATUS = 0
BEGIN
if @temp='A'
BEGIN
set @continuechar=@temp
END
if @temp='C'
BEGIN
set @continuechar=@temp
END
select @continuechar, @temp
FETCH NEXT from Cursor1 into @temp
END
CLOSE cursor1;
deallocate cursor1
在上面的示例代码中,@continuechar 变量未设置,每次执行游标时。如果 @continuechar 正在设置,则以下 select 语句将提供具有 @continuechar 当前值的结果集:
select @continuechar, @temp
如果未设置,则使用先前设置的值来提供结果集。 我们可以设置基于查询来从这种情况下删除游标吗?
首先我会添加一些 id
列以获得稳定的排序。然后简单地使用窗口函数:
SUM() OVER()
计算组数FIRST_VALUE() OVER()
跨组传播第一个值 (来自SQL Server 2012,如有必要,您可以将其与MAX(continuechar) OVER(PARTITION BY grp)
交换)
DECLARE @table1 table (id INT IDENTITY(1,1), col1 varchar(10)) insert into @table1 select 'A' UNION select 'B' UNION select 'C' UNION select 'D' UNION select 'E' UNION select 'F' UNION select 'G'; WITH cte AS ( SELECT id ,col1 ,CASE WHEN col1 IN('A', 'C') THEN col1 END AS continuechar ,SUM(CASE WHEN col1 IN ('A', 'C') THEN 1 ELSE 0 END) OVER(ORDER BY id) AS grp FROM @table1 ) SELECT id, col1, FIRST_VALUE(continuechar) OVER(PARTITION BY grp ORDER BY id) AS continuechar FROM cte ORDER BY id;
编辑:
Quirky update
这仅用于纯演示。不要在生产系统上使用此方法:
DECLARE @table1 table (id INT IDENTITY(1,1) PRIMARY KEY, col1 varchar(10),
continue_char VARCHAR(10));
DECLARE @temp VARCHAR(10);
insert into @table1(col1)
select 'A' UNION
select 'B' UNION
select 'C' UNION
select 'D' UNION
select 'E' UNION
select 'F' UNION
select 'G';
UPDATE @table1
SET @temp = CASE WHEN col1 IN ('A','C') THEN col1 ELSE @temp END
,continue_char = @temp
OPTION(MAXDOP 1);
SELECT *
FROM @table1;