如何动态地将用户传递给"执行用户"从SQL-Transact中的游标?

时间:2016-02-04 17:19:07

标签: sql-server tsql

我需要使用WITH EXECUTE AS CALLER与不同用户执行存储过程(first_procedure)。为了做到这一点,我创建了一个包含有效用户名的表,我尝试使用EXECUTE AS USER语句执行第二个调用第一个过程的过程。

我的第二个程序如下:

BEGIN
    SET NOCOUNT ON;
    DECLARE @LOGIN nvarchar(MAX);
    DECLARE cur CURSOR LOCAL for
        SELECT USERNAME FROM [dbo].[SIM_TABLE] WHERE USERNAME LIKE 'DIJON%';
    OPEN cur
    FETCH NEXT FROM cur INTO @LOGIN;

    WHILE @@FETCH_STATUS = 0
        BEGIN
            PRINT @LOGIN;
            EXECUTE AS USER = @LOGIN;
            EXEC dbo.first_procedure; 
            REVERT;
            FETCH NEXT FROM cur INTO @LOGIN;
        END;
    CLOSE cur
    DEALLOCATE cur
END

我面临的问题是,我真的不知道如何在@LOGIN之后格式化EXECUTE AS USER =部分才能生效。当我影响到@LOGIN的字符串时,它会起作用,但是从光标开始它就不会出现。是否需要进行一些转型?

3 个答案:

答案 0 :(得分:1)

如果你在这里查看EXECUTE AS文档的这一部分 - https://msdn.microsoft.com/en-GB/library/ms181362.aspx#_user - 你会看到它说:

  

EXECUTE AS中指定的用户名或登录名必须作为sys.database_principals或sys.server_principals中的主体存在

这意味着(以及实际上是一个主体 - 即登录)它必须格式化相同。

因此,对于只有username的SQL登录,以及DomainName\username的Windows登录。

您可以按如下方式获取数据库主体列表:

SELECT name FROM sys.database_principals

<强>更新

事实证明,EXECUTE AS语句反对的是@LOGIN变量的nvarchar(MAX)数据类型。它不是nvarchar本身的问题,它是(MAX)。这并不奇怪,因为(MAX)数据类型与固定大小版本的工作方式非常不同。

让我们尝试几个例子:

DECLARE @LOGIN nvarchar(MAX)
SET @LOGIN = N'MyUser'
EXECUTE AS LOGIN = @LOGIN
  

Msg 15533,Level 16,State 2,Line 3

     

“执行为”中提供了无效的数据类型。言。

使用nvarchar(256):

DECLARE @LOGIN nvarchar(256)
SET @LOGIN = N'MyUser'
EXECUTE AS LOGIN = @LOGIN
  

命令已成功完成。

实际上,我建议使用sysname类型,因为这是SQL Server内部用于对象名称的类型 - 尽管在SQL 2008中这只是用于非可空nvarchar(256)的用户定义类型R2起码至少。

答案 1 :(得分:0)

我改变了我的答案,因为下面的评论(在下一个答案中)说表中的用户名是当前的SQL登录名。在这种情况下,您可能应该使用&#34; EXECUTE AS LOGIN&#34;而不是使用&#34; EXECUTE AS USER&#34;。您也可能想要摆脱光标:

BEGIN
   SET NOCOUNT ON
   DECLARE @LOGIN nvarchar(MAX)

   SET @LOGIN = ''

   WHILE 1 = 1 BEGIN

     SELECT TOP 1 @LOGIN = USERNAME
     FROM   [dbo].[SIM_TABLE]
     WHERE  USERNAME LIKE 'DIJON%' AND USERNAME > @LOGIN
     ORDER  BY USERNAME ASC

     IF @@ROWCOUNT = 0 BREAK

     EXECUTE AS LOGIN = @LOGIN
     EXEC dbo.first_procedure 
     REVERT

   END
END    

答案 2 :(得分:0)

经过更多调查,解决方案是施放@LOGIN ......

EXECUTE AS USER = CAST(@LOGIN AS VARCHAR);

我不确定为什么NVARCHAR在这种情况下不起作用,但在VARCHAR中进行投射可以完成工作。