2009-02-03 50 views
0

我通過一系列Sprocs僅通過與數據庫的交互來保護數據庫;很普通的票價。授予跨不同數據庫(模式)的權限

我挖掘並修改了一個腳本,它循環併爲所有非系統SProcs分配用戶EXECUTE權限。除了理想地將其添加到主數據庫以便我可以輕鬆地將其用於任何後續項目之外,它的工作原理是一種享受。是的,我可以簡單地保存爲.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 
+0

你可能想看看一個更清潔,我發現了:SELECT @sp_executesql = QUOTENAME(@dbname)+ '..sp_executesql' EXEC @sp_executesql @ CMD1 – 2009-02-06 16:09:59

回答

2

類同@凱德的答案,要做到這一點的方法是使用動態SQL。在每次調用數據庫表之前,添加'@DbName'。然後將@DbName替換爲實際的數據庫名稱(數據庫名稱不能作爲SQL中的變量傳遞,因此您必須執行替換)。

另外由於性能原因,遊標通常被認爲是邪惡的,但在這種情況下使用遊標是有道理的。首先,它會大大簡化這個過程,再加上你只在應用程序更新期間運行一次,所以即使它增加了一兩個額外的秒或兩個(我懷疑它會在那附近添加任何地方)。

ALTER PROCEDURE [dbo].[spGrantExec] 
@User SysName, 
@DbName VarChar(512) 
AS 
BEGIN 
DECLARE @Sql VarChar(1024)

SET @Sql = 'DECLARE @OwnerName varchar(128) DECLARE @ObjectName varchar(128) DECLARE @Cmd1 VarChar(128) DECLARE ProcCursor CURSOR FOR SELECT ROUTINE SCHEMA, ROUTINE NAME FROM @DbName.INFORMATION SCHEMA.ROUTINES WHERE ROUTINENAME NOT LIKE ''dt %'' AND ROUTINE TYPE = ''PROCEDURE'' OPEN ProcCursor FETCH NEXT FROM ProcCursor INTO @OwnerName, @ObjectName WHILE @@FETCH STATUS = 0 BEGIN SET @CMD1 = ''GRANT EXEC ON '' + ''['' + @OwnerName + '']'' + ''.'' + ''['' + @ObjectName + '']'' + '' TO '' + ''@user'' EXEC (@CMD1)

FETCH NEXT FROM ProcCursor INTO @OwnerName, @ObjectName END CLOSE ProcCursor DEALLOCATE ProcCursor '

SET @Sql = Replace(Replace(@Sql, '@DbName', @DbName), '@user', @User) EXEC (@Sql)

END



可以使用稱之爲:EXEC [spGrantExec] '鮑勃', '羅斯文'

對不起的間距是在SP有點過。

SELECT @sql = 'CREATE VIEW ...' 
SELECT @sp_executesql = quotename(@dbname) + '..sp_executesql' 
EXEC @sp_executesql @sql 

這依賴於在其他數據庫調用sp_executesql的(就像一個可以調用任何數據庫的SP)設置數據庫環境:使用SQL 2005

1

您可以使用the double exec technique

在你的情況,而不是隻:

EXEC(@CMD1) 

你必須:

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

有趣。我可以看到原理,但還沒有消化更精細的細節。但看起來很有希望...... – CJM 2009-02-03 16:01:10

+0

我希望我可以將已經接受的答案分爲獎項 - 無論如何。 – CJM 2009-02-06 10:49:32