四、動態執行
使用動態執行技術,我們能夠更輕松地編寫出GetSortedShippers存儲過程。使用這種方法時,我們只需動態地構造出SELECT語句,然後用EXEC()命令執行這個SELECT語句。假設傳遞給存儲過程的參數是列的名字,存儲過程可以大大縮短:
ALTER PROC GetSortedShippers
@ColName AS sysname
AS
EXEC('SELECT * FROM Shippers ORDER BY ' +
@ColName)
在SQL Server 2000和7.0中,你可以用系統存儲過程sp_ExecuteSQL替代Exec()命令。BOL說明了使用sp_ExecuteSQL比使用Exec()命令更有利的地方。一般地,如果滿足以下三個條件,你能夠在不授予存儲過程所涉及對象權限的情況下,授予執行存儲過程的權限:首先,只使用Data Manipulation Language(DML)語言(即SELECT,INSERT,UPDATE,DELETE);其次,所有被引用的對象都有與存儲過程同樣的所有者;第三,沒有使用動態命令。
上面的存儲過程不能滿足第三個條件。在這種情況下,你必須為所有需要使用存儲過程的用戶和組顯式地授予Shippers表的SELECT權限。如果這一點可以接受的話,一切不存在問題。
類似地,你可以修改存儲過程,使它接受一個列號參數,如Listing 8所示。
【Listing 8:用列號作為參數,動態執行(代碼較長的方法)】
ALTER PROC GetSortedShippers
@ColNumber AS int
AS
DECLARE @cmd AS varchar(8000)
SET @cmd = 'SELECT * FROM Shippers ORDER BY ' +
CASE @ColNumber
WHEN 1 THEN 'ShipperID'
WHEN 2 THEN 'CompanyName'
WHEN 3 THEN 'Phone'
ELSE 'NULL'
END
EXEC(@cmd)
注意,當你使用了函數時,你應該在一個變量而不是EXEC()命令內構造SELECT語句。此時,CASE表達式動態地確定使用哪一個列。還有一種更簡短的格式,T-SQL允許在ORDER BY子句中指定SELECT清單中列的位置,如Listing 9所示。這種格式遵從了SQL-92標准,但ANSI SQL-99標准不支持這種格式,所以最好不要使用這種格式。
【Listing 9:列號作為參數,動態執行(代碼較短的方法)】
ALTER PROC GetSortedShippers
@ColNumber AS int
AS
DECLARE @cmd AS varchar(8000)
SET @cmd = 'SELECT * FROM Shippers ORDER BY ' + CAST(@ColNumber AS varchar(4))
EXEC(@cmd)