執(zhí)行可以多次重用或動態(tài)生成的 Transact-SQL 語句或批處理。Transact-SQL 語句或批處理可以包含嵌入?yún)?shù)。
sp_executesql [@stmt =] stmt
[
{, [@params =] N'@parameter_name data_type [,...n]' }
{, [@param1 =] 'value1' [,...n] }
]
[@stmt =] stmt
包含 Transact-SQL 語句或批處理的 Unicode 字符串,stmt 必須是可以隱式轉(zhuǎn)換為 ntext 的 Unicode 常量或變量。不允許使用更復(fù)雜的 Unicode 表達(dá)式(例如使用 + 運算符串聯(lián)兩個字符串)。不允許使用字符常量。如果指定常量,則必須使用 N 作為前綴。例如,Unicode 常量 N'sp_who' 是有效的,但是字符常量 'sp_who' 則無效。字符串的大小僅受可用數(shù)據(jù)庫服務(wù)器內(nèi)存限制。
stmt 可以包含與變量名形式相同的參數(shù),例如:
N'SELECT * FROM Employees WHERE EmployeeID = @IDParameter'
stmt 中包含的每個參數(shù)在 @params 參數(shù)定義列表和參數(shù)值列表中均必須有對應(yīng)項。
[@params =] N'@parameter_name data_type [,...n]'
字符串,其中包含已嵌入到 stmt 中的所有參數(shù)的定義。該字符串必須是可以隱式轉(zhuǎn)換為 ntext 的 Unicode 常量或變量。每個參數(shù)定義均由參數(shù)名和數(shù)據(jù)類型組成。n 是表明附加參數(shù)定義的占位符。stmt 中指定的每個參數(shù)都必須在 @params 中定義。如果 stmt 中的 Transact-SQL 語句或批處理不包含參數(shù),則不需要 @params。該參數(shù)的默認(rèn)值為 NULL。
[@param1 =] 'value1'
參數(shù)字符串中定義的第一個參數(shù)的值。該值可以是常量或變量。必須為 stmt 中包含的每個參數(shù)提供參數(shù)值。如果 stmt 中包含的 Transact-SQL 語句或批處理沒有參數(shù),則不需要值。
n
附加參數(shù)的值的占位符。這些值只能是常量或變量,而不能是更復(fù)雜的表達(dá)式,例如函數(shù)或使用運算符生成的表達(dá)式。
0(成功)或 1(失?。?/P>
從生成 SQL 字符串的所有 SQL 語句返回結(jié)果集。
在批處理、名稱作用域和數(shù)據(jù)庫上下文方面,sp_executesql 與 EXECUTE 的行為相同。sp_executesql stmt 參數(shù)中的 Transact-SQL 語句或批處理在執(zhí)行 sp_executesql 語句時才編譯。然后編譯 stmt 中的內(nèi)容并作為執(zhí)行計劃運行(獨立于名為 sp_executesql 的批處理的執(zhí)行計劃)。sp_executesql 批處理不能引用調(diào)用 sp_executesql 的批處理中聲明的變量。sp_executesql 批處理中的本地游標(biāo)和變量對調(diào)用 sp_executesql 的批處理是不可見的。對數(shù)據(jù)庫上下文所作的更改只在 sp_executesql 語句結(jié)束前有效。
如果只更改了語句中的參數(shù)值,則 sp_executesql 可用來代替存儲過程多次執(zhí)行 Transact-SQL 語句。因為 Transact-SQL 語句本身保持不變僅參數(shù)值變化,所以 Microsoft® SQL Server™ 查詢優(yōu)化器可能重復(fù)使用首次執(zhí)行時所生成的執(zhí)行計劃。
說明 如果語句字符串中的對象名不是全限定名,則該執(zhí)行計劃不會被重用。
sp_executesql 支持與 Transact-SQL 字符串相獨立的參數(shù)值的設(shè)置:
DECLARE @IntVariable INT
DECLARE @SQLString NVARCHAR(500)
DECLARE @ParmDefinition NVARCHAR(500)
/* Build the SQL string once.*/
SET @SQLString =
N'SELECT * FROM pubs.dbo.employee WHERE job_lvl = @level'
SET @ParmDefinition = N'@level tinyint'
/* Execute the string with the first parameter value. */
SET @IntVariable = 35
EXECUTE sp_executesql @SQLString, @ParmDefinition,
@level = @IntVariable
/* Execute the same string with the second parameter value. */
SET @IntVariable = 32
EXECUTE sp_executesql @SQLString, @ParmDefinition,
@level = @IntVariable
替換 sp_executesql 中的參數(shù)的能力,與使用 EXECUTE 語句執(zhí)行字符串相比,有下列優(yōu)點:
執(zhí)行權(quán)限默認(rèn)授予 public 角色。
下面的示例創(chuàng)建并執(zhí)行一個簡單的 SELECT 語句,其中包含名為 @level 的嵌入?yún)?shù)。
execute sp_executesql
N'select * from pubs.dbo.employee where job_lvl = @level',
N'@level tinyint',
@level = 35
下面的示例顯示使用 sp_executesql 執(zhí)行動態(tài)生成的字符串。該示例中的存儲過程用來向一組表中插入數(shù)據(jù),該表用于劃分一年的銷售數(shù)據(jù)。一年中的每個月均有一個表,格式如下:
CREATE TABLE May1998Sales
(OrderID INT PRIMARY KEY,
CustomerID INT NOT NULL,
OrderDate DATETIME NULL
CHECK (DATEPART(yy, OrderDate) = 1998),
OrderMonth INT
CHECK (OrderMonth = 5),
DeliveryDate DATETIME NULL,
CHECK (DATEPART(mm, OrderDate) = OrderMonth)
)
有關(guān)從這些分區(qū)表中檢索數(shù)據(jù)的更多信息,請參見使用包含分區(qū)數(shù)據(jù)的視圖。
每個表的名稱由月份名的前三個字母、年度的四位數(shù)字和常量 Sales 組成。名稱可以從訂單日期動態(tài)生成:
/* Get the first three characters of the month name. */
SUBSTRING( DATENAME(mm, @PrmOrderDate), 1, 3) +
/* Concatenate the four-digit year; cast as character. */
CAST(DATEPART(yy, @PrmOrderDate) AS CHAR(4) ) +
/* Concatenate the constant 'Sales'. */
'Sales'
下面示例中的存儲過程動態(tài)生成并執(zhí)行一個 INSERT 語句,向適當(dāng)?shù)谋碇胁迦胄掠唵?。該存儲過程使用訂單日期生成應(yīng)包含數(shù)據(jù)的表的名稱,然后將名稱并入 INSERT 語句。(這是 sp_executesql 的一個簡單示例。不包含錯誤檢查,也不包括業(yè)務(wù)規(guī)則檢查,例如確保兩個表之間訂單號沒有重復(fù)。)
CREATE PROCEDURE InsertSales @PrmOrderID INT, @PrmCustomerID INT,
@PrmOrderDate DATETIME, @PrmDeliveryDate DATETIME
AS
DECLARE @InsertString NVARCHAR(500)
DECLARE @OrderMonth INT
-- Build the INSERT statement.
SET @InsertString = 'INSERT INTO ' +
/* Build the name of the table. */
SUBSTRING( DATENAME(mm, @PrmOrderDate), 1, 3) +
CAST(DATEPART(yy, @PrmOrderDate) AS CHAR(4) ) +
'Sales' +
/* Build a VALUES clause. */
' VALUES (@InsOrderID, @InsCustID, @InsOrdDate,' +
' @InsOrdMonth, @InsDelDate)'
/* Set the value to use for the order month because
functions are not allowed in the sp_executesql parameter
list. */
SET @OrderMonth = DATEPART(mm, @PrmOrderDate)
EXEC sp_executesql @InsertString,
N'@InsOrderID INT, @InsCustID INT, @InsOrdDate DATETIME,
@InsOrdMonth INT, @InsDelDate DATETIME',
@PrmOrderID, @PrmCustomerID, @PrmOrderDate,
@OrderMonth, @PrmDeliveryDate
GO
在該過程中使用 sp_executesql 比使用 EXECUTE 執(zhí)行字符串更有效。使用 sp_executesql 時,只生成 12 個版本的 INSERT 字符串,每個月的表 1 個。使用 EXECUTE 時,因為參數(shù)值不同,每個 INSERT 字符串均是唯一的。盡管兩種方法生成的批處理數(shù)相同,但因為 sp_executesql 生成的 INSERT 字符串相似,所以查詢優(yōu)化程序更有可能反復(fù)使用執(zhí)行計劃。