【问题标题】:Select as different user works in query but not in Stored Procedure选择不同的用户在查询中工作但不在存储过程中
【发布时间】:2018-05-07 02:33:07
【问题描述】:

环境:SQL SERVER 2016 我在 SQL 中使用 execute as user 函数来创建特定于会话的表,而不使用动态 SQL。当我将代码作为单个查询运行时,它的执行完全符合预期。工作代码是:

    DECLARE @strSQL NVARCHAR(MAX)
    , @strSession AS NVARCHAR(256) 
    SET @strSession = 'SESSION_ABCD'

    SET @strSQL = 'CREATE SCHEMA ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'CREATE LOGIN ' + @strSession + ' WITH PASSWORD = ''' + CAST(NEWID() AS NVARCHAR(36)) + ''' '
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'CREATE USER ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'ALTER USER ' + @strSession + ' WITH DEFAULT_SCHEMA = ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'GRANT ALTER ON SCHEMA::' + @strSession + ' TO ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)      

    SET @strSQL = 'GRANT CREATE TABLE TO ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'GRANT SELECT,INSERT,UPDATE,DELETE TO ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)

    EXECUTE AS USER = 'SESSION_ABCD'

    -- Create table without including default schema - OK
    -- Creates table SESSION_ABCD.Test as expected
    CREATE TABLE Test (MyValue INT)

    -- Select from table including schema name - OK         
    SELECT  *
    FROM    SESSION_ABCD.Test

    -- Select from table excluding schema name - Works outside of stored procedure
    SELECT  *
    FROM    Test

    REVERT

但是,如果我在存储的 [过程中运行相同的代码,我会得到意想不到的结果。代码如下:

CREATE PROC dbo.SetupUser
AS
BEGIN
    DECLARE @strSession AS NVARCHAR(256) 
    SET @strSession = 'SESSION_ABCD'

    DECLARE @strSQL NVARCHAR(MAX)

    SET @strSQL = 'CREATE SCHEMA ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'CREATE LOGIN ' + @strSession + ' WITH PASSWORD = ''' + CAST(NEWID() AS NVARCHAR(36)) + ''' '
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'CREATE USER ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'ALTER USER ' + @strSession + ' WITH DEFAULT_SCHEMA = ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'GRANT ALTER ON SCHEMA::' + @strSession + ' TO ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)      

    SET @strSQL = 'GRANT CREATE TABLE TO ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)

    SET @strSQL = 'GRANT SELECT,INSERT,UPDATE,DELETE TO ' + @strSession
    PRINT (@strSQL) 
    EXEC (@strSQL)
END

GO

CREATE PROC dbo.SetupTable
AS
BEGIN

    EXECUTE AS USER = 'SESSION_ABCD'

    -- Create table without including default schema - OK
    -- Creates table SESSION_ABCD.Test as expected
    CREATE TABLE Test (MyValue INT)

    -- Select from table including schema name - OK         
    SELECT  *
    FROM    SESSION_ABCD.Test

    -- Select from table excluding schema name - Fails
    -- Expecting same result as above

    PRINT SCHEMA_NAME()
    SELECT  *
    FROM    Test

    REVERT
END

GO

EXEC dbo.SetupUser

EXEC dbo.SetupTable

当我执行上面的脚本时,用户/会话/等配置正确。 (请注意,您需要从系统中删除它们才能再次运行它们。)在 SetupTable 过程中,create table 命令针对默认模式执行,但是 select 命令需要使用模式名称进行限定。虽然我可以使用动态 SQL 构建查询以插入架构名称,但这个项目完全是围绕删除旧的动态 sql 代码。

老实说,这不是我以前使用过的方法,但似乎是解决另一个问题的最建议的解决方案。我希望我缺少一些基本的东西,但现在我完全被难住了。

非常感谢。

【问题讨论】:

    标签: sql-server stored-procedures permissions schema sql-server-2016


    【解决方案1】:

    您的第二个过程是在 dbo 架构中创建的,如果您没有在其中使用完全限定名称,则默认架构是 存储过程架构(在您的情况下为 dbo),而不是用户的默认架构。

    例如,您的用户 A 具有默认架构 a、架构 B, 和架构 dbo

    你创建一个过程 B.sp_test:

    create proc B.sp_test as select * from test_tbl
    

    现在用户 A 执行这个 sp。

    test_tbl 不是架构限定的,因此服务器首先查找B.test_tbl。 如果表存在,则从中进行选择。如果没有,它会寻找dbo.test_tbl。 如果未找到该表,则说明出现错误。

    验证的不是用户的默认架构,而是过程的架构,然后是 dbo 架构。

    这与创建表不同。 当用户创建表而不使用模式限定它时,将使用它的默认 scema。这与创建表的位置无关,无论是否在 sp 内。

    如何向自己证明这一点?

    只需在不同的架构中创建一个过程。 创建 3 个同名 test_tbl 的表,将它们放入您的默认模式、dbo 和 sp 模式中。 在每个表中插入它的架构名称。

    在 sp 中从 test_tbl 中进行 SELECT,当所有 3 个表都存在时运行它。 您将从 sp 架构中的表中获取数据。

    现在删除这个表,再次运行 sp。

    这次您将从 dbo.test_tbl 获取数据。

    最后,删除 dbo.test_tbl,运行 sp。这次你会得到一个错误。

    【讨论】:

    • 正确。我必须找到解决办法。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2013-03-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多