Its always been discouraged to use cursor, which have been extensively used in our current stored procedures and replace them with set based queries. But this particular scenario is one, where I did not get solution to use set based query and forced to keep using the cursor. I am providing below sample code which represents the scenario:
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
Here in above sample code @continuechar variable is not getting set, every time cursor is getting executed. If @continuechar is getting set, then following select statement is providing result set with current value of @continuechar:
select @continuechar, @temp
if its not getting set, then its using the previously set value to provide result set. Can we have set based queries to remove cursor from such scenario.
First I would add some id
column to get stable sort. Then simply use windowed functions:
SUM() OVER()
to calculate groupsFIRST_VALUE() OVER()
to propagate first value across group
(present from SQL Server 2012, you could exchange it with MAX(continuechar) OVER(PARTITION BY grp)
if necessary)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;
EDIT:
Quirky update
This is for pure demo only. Do not use this method on production system:
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;