web-dev-qa-db-fra.com

Utiliser le curseur pour mettre à jour s'il existe et insérer sinon

J'essaie d'écrire un curseur. J'ai créé un tableau pour capturer le nom et l'heure de connexion à partir de sys.dm_exec_sessions. Maintenant, je dois écrire un curseur pour mettre à jour l'heure de connexion à la dernière heure de connexion si la connexion existe déjà et insérer une ligne au cas où la connexion n'existe pas dans ma table. J'ai trouvé la suite, mais malheureusement, je reçois une erreur avec la sous-requête renvoyant plus d'une valeur pour elle. Des idées???

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
2
Jay

Je pense que cette erreur est générée à cause de cette ligne

If (Select Login from [dbo].[LoginsForDBUserList])  = @log

Plusieurs lignes sont renvoyées du côté gauche du signe égal et tentent d'être comparées à la valeur unique @log.

J'ai apporté quelques ajustements à votre requête d'origine et cela fonctionne pour moi. Essayez ceci:

--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
4
Scott Hodgin

@Scott a déjà donné la réponse à votre question. Mais j'espère que vous pourrez abandonner ce curseur et utiliser un code basé sur SET ici.

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;
1
Biju jose