DECLARE @tbl TABLE(ckid INT,stat VARCHAR(10) )INSERT INTO @tblSELECT 101 ,'Open' UNION ALLSELECT 102 ,'Open' UNION ALLSELECT 103 ,'Open' UNION ALLSELECT 104 ,'Void' UNION ALLSELECT 105 ,'Void' UNION ALLSELECT 106 ,'Open' UNION ALLSELECT 107 ,'Open' UNION ALLSELECT 108 ,'Open' UNION ALLSELECT 109 ,'Void' UNION ALLSELECT 110 ,'Open'SELECT *FROM @tbl;WITH cte AS -- row number per group( SELECT *, ROW_NUMBER() OVER(ORDER BY ckid) r1, ROW_NUMBER() OVER(ORDER BY ckid)- ROW_NUMBER() OVER(PARTITION BY stat ORDER BY ckid ) AS ROW FROM @tbl),cte2 AS -- row number per group range, ordered by ckid( SELECT MIN(r1) mi,MAX(r1) ma,stat,ROW, ROW_NUMBER() OVER(ORDER BY MIN(r1) ) r2 FROM cte GROUP BY stat,ROW)SELECT ckid ,cte.stat,cte2.r2FROM cteINNER JOIN cte2 ON r1>=mi AND r1<=maORDER BY r1
IF OBJECT_ID('tempdb..#temp') IS NOT NULL DROP TABLE #temp;-- This primary key is crucial. If your table doesn't have a clustered index-- on this, then you will have to dump the data to a temp table (along with -- the PK columns of the table), use this PK, then update the real table-- by joining this temp table back to the real table by the PK columns.CREATE TABLE #temp (ckid INT PRIMARY KEY CLUSTERED, stat varchar(10), Grp int);INSERT INTO #temp (ckid, stat)SELECT 101 ,'Open' UNION ALLSELECT 102 ,'Open' UNION ALLSELECT 103 ,'Open' UNION ALLSELECT 104 ,'Void' UNION ALLSELECT 105 ,'Void' UNION ALLSELECT 106 ,'Open' UNION ALLSELECT 107 ,'Open' UNION ALLSELECT 108 ,'Open' UNION ALLSELECT 109 ,'Void' UNION ALLSELECT 110 ,'Open';-- declare and initialize variables needed in the update statement.DECLARE @Sequence int, -- for safety check @stat varchar(10), -- to hold stat column from last row @grp int, -- current grp number @ckid int; -- for anchor columnSET @Sequence = 1;SET @grp = 1;/*This form of the UPDATE statement has some rules for proper usage.See Jeff Moden's article at http://www.sqlservercentral.com/articles/T-SQL/68467/for a complete discussion of how this works, and all of the rules for utilizing it.If you don't follow ALL the rules, you WILL mess up your data.*/WITH SafeTable AS(-- generate table with a sequence column in clustered index order -- in order to verify that update is happening in the correct orderSELECT ckid, stat, grp, Sequence = ROW_NUMBER() OVER (ORDER BY ckid) FROM #temp)UPDATE t -- verify in proper sequence order; if not, throw an error so nothing is updated SET @grp = grp = CASE WHEN Sequence = @Sequence THEN CASE WHEN stat <> @Stat THEN @grp + 1-- if you have to separate this by account numbers also, then you will need-- a when clause to handle it here also. -- different stat --> increment grp number ELSE @grp END -- same stat --> same grp number ELSE 1/0 END, -- not in proper sequence order, so throw an error @Sequence = @Sequence + 1, @stat = stat, -- get the current value to compare to in next row @ckid = ckid -- anchor column FROM SafeTable t WITH (TABLOCKX) -- lock table OPTION (MAXDOP 1); -- prevent parallelism!select * from #temp;