Sql server 跨不同数据库(架构)授予权限

Sql server 跨不同数据库(架构)授予权限,sql-server,sql-server-2005,tsql,permissions,Sql Server,Sql Server 2005,Tsql,Permissions,我只允许通过一系列存储过程与数据库进行交互,从而保护数据库;相当普通的票价 我已经挖掘并修改了一个脚本,该脚本循环并为所有非系统存储过程分配用户执行权限。它非常有用,除了我希望将其添加到主数据库中,以便我可以轻松地将其用于任何后续项目。是的,我可以将simple保存为.sql文件,但我更喜欢这种方式 问题是我不知道如何动态引用另一个数据库中的对象。例如,我可以轻松地查询MyDB.dbo.INFORMATION_SCHEMA.ROUTINES,但如果数据库名是动态的(例如@MyDBName),我如

我只允许通过一系列存储过程与数据库进行交互,从而保护数据库;相当普通的票价

我已经挖掘并修改了一个脚本,该脚本循环并为所有非系统存储过程分配用户执行权限。它非常有用,除了我希望将其添加到主数据库中,以便我可以轻松地将其用于任何后续项目。是的,我可以将simple保存为.sql文件,但我更喜欢这种方式

问题是我不知道如何动态引用另一个数据库中的对象。例如,我可以轻松地查询MyDB.dbo.INFORMATION_SCHEMA.ROUTINES,但如果数据库名是动态的(例如@MyDBName),我如何查询该数据库中的对象

编辑:多亏了下面的海报,我现在有了一个可行的解决方案:

USE [master]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO


ALTER PROCEDURE [dbo].[spGrantExec] 
@User sysname,
@DB varchar(50),
@Target varchar(50)
AS 
/*---------------------------- SQL 2005 + -------------------------------*/

SET NOCOUNT ON

-- 1 - Variable declarations
DECLARE @SQL varchar(8000)

-- 2 - Create temporary table
Set @SQL =
'USE @DB

DECLARE @MAXOID int
DECLARE @OwnerName varchar(128)
DECLARE @ObjectName varchar(128)
DECLARE @CMD1 varchar(8000)

CREATE TABLE #StoredProcedures
(OID int IDENTITY (1,1),
StoredProcOwner varchar(128) NOT NULL,
StoredProcName varchar(128) NOT NULL)

-- 3 - Populate temporary table

INSERT INTO #StoredProcedures (StoredProcOwner, StoredProcName)
SELECT ROUTINE_SCHEMA, ROUTINE_NAME
FROM INFORMATION_SCHEMA.ROUTINES 
WHERE ROUTINE_NAME LIKE ''' + @Target + '%''
 AND ROUTINE_TYPE = ''PROCEDURE''

-- 4 - Capture the @MAXOID value
SELECT @MAXOID = MAX(OID) FROM #StoredProcedures

-- 5 - WHILE loop
WHILE @MAXOID > 0
 BEGIN 

    -- 6 - Initialize the variables
    SELECT @OwnerName = StoredProcOwner,
    @ObjectName = StoredProcName
    FROM #StoredProcedures
    WHERE OID = @MAXOID

    -- 7 - Build the string

    SELECT @CMD1 = ''GRANT EXEC ON '' + ''['' + @OwnerName + '']'' + ''.'' + ''['' + @ObjectName + '']'' + '' TO @user''

    -- 8 - Execute the string
    Print @CMD1
    EXEC(@CMD1)

    -- 9 - Decrement @MAXOID
    SET @MAXOID = @MAXOID - 1
 END

-- 10 - Drop the temporary table
DROP TABLE #StoredProcedures'

Set @SQL = REPLACE(REPLACE(REPLACE(@SQL, '@DB', @DB), '@User', @User), '@Target', @Target)
--Select @SQL
--Print @SQL
Exec (@SQL)
SET NOCOUNT OFF
你可以用

在您的情况下,而不仅仅是:

EXEC(@CMD1)
你应该:

SET @CMD1 =
    'USE OtherDatabase;
    EXEC (''' + REPLACE(@CMD1, '''', '''''') + ''')'
EXEC(@CMD1)
你可以用

在您的情况下,而不仅仅是:

EXEC(@CMD1)
你应该:

SET @CMD1 =
    'USE OtherDatabase;
    EXEC (''' + REPLACE(@CMD1, '''', '''''') + ''')'
EXEC(@CMD1)

与@Cade的答案类似,实现这一点的方法是使用动态sql。在每次调用数据库表之前,添加'@DbName'。然后用实际的数据库名称替换@DbName(数据库名称不能在SQL中作为变量传递,因此必须进行替换)

此外,出于性能原因,游标通常被认为是有害的,但是在这种情况下使用游标是有意义的。首先,它将极大地简化过程,而且由于在应用程序更新期间只运行一次,因此您可能不会注意到性能下降,即使它额外增加了一两秒钟(我怀疑它是否会增加这么多)

ALTER过程[dbo]。[spGrantExec]
@用户系统名,
@DbName VarChar(512)
作为
开始
声明@Sql VarChar(1024)

SET@Sql='声明@OwnerName varchar(128) 声明@ObjectName varchar(128) 声明@Cmd1 VarChar(128) 声明的ProcCursor 选择例程模式、例程名称 FROM@DbName.INFORMATION SCHEMA.ROUTINES 其中ROUTINENAME与“dt%”不同,而例程类型为“过程” 打开游标 从ProcCursor获取下一个到@OwnerName、@ObjectName 而@@FETCH STATUS=0 开始 将“++”['+@OwnerName+'''+''.+'.['+@ObjectName+''.+'.+'.]上的@CMD1=''GRANT EXEC设置为“++'.@user” EXEC(@CMD1)

从ProcCursor获取下一个到@OwnerName、@ObjectName 结束 关闭光标 取消分配程序游标 "

设置@Sql=Replace(Replace(@Sql、@DbName、@DbName)、@user、@user) EXEC(@Sql)

结束


您可以使用EXEC[spGrantExec]“bob”、“Northwind”来调用它


抱歉,在使用Sql 2005开发的sp中,间距有点过大。

与@Cade的答案类似,实现这一点的方法是使用动态Sql。在每次调用数据库表之前,添加'@DbName'。然后用实际的数据库名称替换@DbName(数据库名称不能在SQL中作为变量传递,因此必须进行替换)

此外,出于性能原因,游标通常被认为是有害的,但是在这种情况下使用游标是有意义的。首先,它将极大地简化过程,而且由于在应用程序更新期间只运行一次,因此您可能不会注意到性能下降,即使它额外增加了一两秒钟(我怀疑它是否会增加这么多)

ALTER过程[dbo]。[spGrantExec]
@用户系统名,
@DbName VarChar(512)
作为
开始
声明@Sql VarChar(1024)

SET@Sql='声明@OwnerName varchar(128) 声明@ObjectName varchar(128) 声明@Cmd1 VarChar(128) 声明的ProcCursor 选择例程模式、例程名称 FROM@DbName.INFORMATION SCHEMA.ROUTINES 其中ROUTINENAME与“dt%”不同,而例程类型为“过程” 打开游标 从ProcCursor获取下一个到@OwnerName、@ObjectName 而@@FETCH STATUS=0 开始 将“++”['+@OwnerName+'''+''.+'.['+@ObjectName+''.+'.+'.]上的@CMD1=''GRANT EXEC设置为“++'.@user” EXEC(@CMD1)

从ProcCursor获取下一个到@OwnerName、@ObjectName 结束 关闭光标 取消分配程序游标 "

设置@Sql=Replace(Replace(@Sql、@DbName、@DbName)、@user、@user) EXEC(@Sql)

结束


您可以使用EXEC[spGrantExec]“bob”、“Northwind”来调用它

抱歉,使用Sql 2005开发的sp中的间距有点过大。

我发现:

这依赖于通过在另一个数据库中调用sp_executesql来设置数据库上下文(就像可以在任何数据库中调用sp一样)

在您的情况下,这相当于:

SELECT @sp_executesql = quotename(@dbname) + '..sp_executesql'
EXEC @sp_executesql @CMD1 
我发现:

这依赖于通过在另一个数据库中调用sp_executesql来设置数据库上下文(就像可以在任何数据库中调用sp一样)

在您的情况下,这相当于:

SELECT @sp_executesql = quotename(@dbname) + '..sp_executesql'
EXEC @sp_executesql @CMD1 

有趣。我可以看到原理,但还没有理解更详细的细节。但是看起来很有希望…我希望我能为被接受的答案分得一个奖项-无论如何谢谢。很有趣。我可以看到原理,但还没有理解更详细的细节。但是看起来很有希望…我希望我能为被接受的答案平分奖金-无论如何谢谢。你可能想看看我找到的更干净的一个:选择@sp_executesql=quotename(@dbname)+“…sp_executesql”EXEC@sp_executesql@cmd1你可能想看看我找到的更干净的一个:选择@sp_executesql=quotename(@dbname)+“…sp_executesql”EXEC@sp_executesql@CMD1Thanks。下周我会看看这个。谢谢。下周我会看看这个。