web-dev-qa-db-ja.com

存在する場合はカーソルを使用して更新し、存在しない場合は挿入する

カーソルを書こうとしています。 sys.dm_exec_sessionsからログイン名と時刻を取得するためのテーブルを作成しました。ここで、ログインがすでに存在する場合、ログイン時間を最後のログイン時間に更新するカーソルを記述し、ログインがテーブルに存在しない場合に行を挿入する必要があります。私は以下を思いつきましたが、残念ながら、サブクエリが複数の値を返すというエラーが発生します。何か案は???

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

この行が原因でエラーが発生していると思います

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

等号の左側から複数の行が返され、単一の値@logと比較しようとしています。

元のクエリにいくつかの調整を加えましたが、うまくいきました。これを試してみてください:

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

@スコットはあなたの質問に対する回答をすでに与えています。しかし、そのカーソルを捨てて、SETベースのコードをここで使用できることを願っています。

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