Using cursor to update if exists and insert if not
-
12-01-2021 - |
Question
I am trying to write a cursor. I have created a table for capturing login name and time from sys.dm_exec_sessions. Now, I need to write a cursor to update the login time to last login time if the login already exists and insert a row in case login does not exists in my table. I have come up with following, but unfortunately I am getting an error with subquery returning more than one value for it. Any ideas???
declare @log as varchar(200)
declare @log_time as datetime
declare LoginsSize cursor for
SELECT login_name, login_time
FROM sys.dm_exec_sessions
open LoginsSize
fetch next from LoginsSize into @log, @log_time
while( @@fetch_status = 0)
begin
If (Select Login from [dbo].[LoginsForDBUserList]) = @log
Begin
UPDATE [dbo].[LoginsForDBUserList]
SET LastLoginTime = @log_time
WHERE [login]= @log
END
Else
Begin
Insert Into [dbo].[LoginsForDBUserList]
SELECT login_name, login_time
FROM sys.dm_exec_sessions
END
fetch next from LoginsSize into @log, @log_time
close LoginsSize
deallocate LoginsSize
end
Solution
I think that error is being generated because of this line
If (Select Login from [dbo].[LoginsForDBUserList]) = @log
Multiple rows are being returned from the left side of the equal sign and is attempting to be compared to the single value @log
.
I've made some adjustments to your original query and it works for me. Give this a try:
--demo setup
DROP TABLE IF EXISTS LoginsForDBUserList
GO
CREATE TABLE LoginsForDBUserList (
LOGIN VARCHAR(200)
,LastLoginTime DATETIME
)
--Adjustments to your original process
DECLARE @log AS VARCHAR(200)
DECLARE @log_time AS DATETIME
DECLARE LoginsSize CURSOR
FOR
SELECT login_name
,login_time
FROM sys.dm_exec_sessions
OPEN LoginsSize
FETCH NEXT
FROM LoginsSize
INTO @log
,@log_time
WHILE (@@fetch_status = 0)
BEGIN
IF EXISTS (
SELECT LOGIN
FROM LoginsForDBUserList
WHERE LOGIN = @log
)
BEGIN
UPDATE LoginsForDBUserList
SET LastLoginTime = @log_time
WHERE [login] = @log
END
ELSE
BEGIN
INSERT INTO LoginsForDBUserList
SELECT login_name
,login_time
FROM sys.dm_exec_sessions
END
FETCH NEXT
FROM LoginsSize
INTO @log
,@log_time
END
CLOSE LoginsSize
DEALLOCATE LoginsSize
SELECT *
FROM LoginsForDBUserList
OTHER TIPS
@Scott has already given the answer to your question. But I hope you can ditch that cursor and use a SET based code here.
UPDATE a
SET LastLoginTime = b.login_time
FROM [dbo].[LoginsForDBUserList] a
JOIN sys.dm_exec_sessions b
ON a.login = b.login_name;
IF EXISTS ( SELECT 1
FROM sys.dm_exec_sessions b
LEFT JOIN [dbo].[LoginsForDBUserList] a
ON a.login = b.login_name
WHERE a.login IS NULL)
BEGIN
INSERT INTO [dbo].[LoginsForDBUserList]
SELECT login_name,
login_time
FROM sys.dm_exec_sessions b
LEFT JOIN [dbo].[LoginsForDBUserList] a
ON a.login = b.login_name
WHERE a.login IS NULL;
END;