Microsoft SQL Server Cursors
Had to do some sequential merging of records in sql data and this is one of the few occasions when a cursor is useful and it had been quite awhile since I had written a cursor and refreshed my memory with this.
Need to merge records from a table that used to have uniqueness on the Id
field to now have uniqueness across StartTime, EndTime, AccountNumber
and then merge up the notes into a single record.
Using a merge
statement to accomplish this along with the cursor retrieval
DROP TABLE IF EXISTS #FirstTable
CREATE TABLE #FirstTable
(
Id INT NOT NULL PRIMARY KEY IDENTITY(1,1),
AccountNumber VARCHAR(10),
StartTime DATETIME,
EndTime DATETIME,
Note VARCHAR(100)
)
INSERT INTO #FirstTable
(
AccountNumber,
StartTime,
EndTime,
Note
)
VALUES
(
'12345', -- AccountNumber - varchar(10)
'2021-01-01', -- StartTime - datetime
'2021-01-05', -- EndTime - datetime
'First Note' -- Note varchar(100)
),
(
'12345', -- AccountNumber - varchar(10)
'2021-01-01', -- StartTime - datetime
'2021-01-05', -- EndTime - datetime,
'Second Note' -- Note varchar(100)
),
(
'54321', -- AccountNumber - varchar(10)
'2021-02-01', -- StartTime - datetime
'2021-02-02', -- EndTime - datetime,
'Yep notes' -- Note varchar(100)
),
(
'00001', -- AccountNumber - varchar(10)
'2021-02-01', -- StartTime - datetime
'2021-02-06', -- EndTime - datetime,
NULL
)
DROP TABLE IF EXISTS #RevisedTable;
CREATE TABLE #RevisedTable
(
AccountNumber VARCHAR(10),
StartTime DATETIME,
EndTime DATETIME,
Note VARCHAR(100)
)
DECLARE @start DATETIME;
DECLARE @end DATETIME;
DECLARE @account VARCHAR(10);
DECLARE @id INT;
DECLARE @note VARCHAR(MAX);
-- declare cursor
DECLARE my_cursor CURSOR FOR
SELECT Id,
AccountNumber,
StartTime,
EndTime,
Note
FROM #FirstTable
ORDER BY Id DESC;
-- open cursor
OPEN my_cursor;
FETCH NEXT FROM my_cursor INTO @id, @account, @start, @end, @note;
WHILE @@FETCH_STATUS = 0
BEGIN
PRINT CONCAT('id: ', @id, 'account: ', @account, ' start: ', @start, ' end: ', @end, ' note:', @note);
MERGE #RevisedTable AS [target]
USING (
VALUES
(
@id,
@account,
@start,
@end,
@note
)
) AS [source] (
Id,
AccountNumber,
StartTime,
EndTime,
Note)
ON (
[target].[StartTime] = [source].[StartTime] AND
[target].[EndTime] = [source].[EndTime] AND
[target].[AccountNumber] = [source].[AccountNumber]
)
WHEN NOT MATCHED THEN
INSERT(AccountNumber,
StartTime,
EndTime,
Note)
VALUES([source].[AccountNumber],
[source].[StartTime],
[source].[EndTime],
NULLIF(SUBSTRING([source].[Note], 0, 100), ''))
WHEN MATCHED THEN
UPDATE SET [target].[Note] = NULLIF(SUBSTRING(CONCAT([target].[Note], ' Id=[' + CAST([source].[Id] as varchar(10)) + ']: ', [source].[Note]), 0, 100), '');
FETCH NEXT FROM my_cursor INTO @id, @account, @start, @end, @note;
END;
-- close and deallocate cursor
CLOSE my_cursor;
DEALLOCATE my_cursor;
SELECT *
FROM #RevisedTable
ORDER BY AccountNumber
AccountNumber StartTime EndTime Note CreatedAt
00001 2021-02-01 00:00:00.000 2021-02-06 00:00:00.000 NULL 2021-05-04 15:23:35.780
12345 2021-01-01 00:00:00.000 2021-01-05 00:00:00.000 Second Note Id=[1]: First Note 2021-05-04 15:23:35.780
54321 2021-02-01 00:00:00.000 2021-02-02 00:00:00.000 Yep notes 2021-05-04 15:23:35.780
SELECT *
FROM #FirstTable
ORDER BY AccountNumber
Id AccountNumber StartTime EndTime Note
4 00001 2021-02-01 00:00:00.000 2021-02-06 00:00:00.000 NULL
1 12345 2021-01-01 00:00:00.000 2021-01-05 00:00:00.000 First Note
2 12345 2021-01-01 00:00:00.000 2021-01-05 00:00:00.000 Second Note
3 54321 2021-02-01 00:00:00.000 2021-02-02 00:00:00.000 Yep notes