表值參數是 SQL Server 2008 中的新參數類型。表值參數是使用用戶定義的表類型來聲明的。使用表值參數,可以不必創建臨時表或許多參數,即可向 Transact-SQL 語句或例程(如存儲過程或函數)發送多行數據。
??表值參數與 OLE DB 和 ODBC 中的參數數組類似,但具有更高的靈活性,且與 Transact-SQL 的集成更緊密。表值參數的另一個優勢是能夠參與基于數據集的操作。
在 Transact-SQL 中創建和使用表值參數
表值參數具有兩個主要部分:SQL Server 類型以及引用該類型的參數。若要創建和使用表值參數,請執行以下步驟:
??1.創建表類型并定義表結構。
??2.聲明具有表類型參數的例程(CREATE PROCEDURE/FUNCTION)。
??3.聲明表類型變量,并引用該表類型。
??4.使用INSERT語句填充表變量。
??5.創建并填充表變量后,可以將該變量傳遞給例程。
優點
??表值參數具有更高的靈活性,在某些情況下,可比臨時表或其他傳遞參數列表的方法提供更好的性能。表值參數具有以下優勢:
- 首次從客戶端填充數據時,不獲取鎖。
- 提供簡單的編程模型。
- 允許在單個例程中包括復雜的業務邏輯。
- 減少到服務器的往返。
- 可以具有不同基數的表結構。
- 是強類型。
- 使客戶端可以指定排序順序和唯一鍵。
限制
??表值參數有下面的限制:
- SQL Server 不維護表值參數列的統計信息。
- 表值參數必須作為輸入 READONLY 參數傳遞到 Transact-SQL 例程。不能在例程體中對表值參數執行諸如 UPDATE、DELETE 或 INSERT 這樣的 DML 操作。
- 不能將表值參數用作 SELECT INTO 或 INSERT EXEC 語句的目標。表值參數可以在 SELECT INTO 的 FROM 子句中,也可以在 INSERT EXEC 字符串或存儲過程中。
- 不能將表值參數指定為 INSERT EXEC 語句的目標;但是,可以將它指定為 INSERT EXEC 字符串或存儲過程中的源。
作用域
??就像其他參數一樣,表值參數的作用域也是存儲過程、函數或動態 Transact-SQL 文本。同樣,表類型變量也與使用 DECLARE 語句創建的其他任何局部變量一樣具有作用域??梢栽趧討B Transact-SQL 語句內聲明表值變量,并且可以將這些變量作為表值參數傳遞到存儲過程和函數。
用戶定義表類型
在 SQL Server 2008 中,用戶定義表類型是指用戶所定義的表示表結構定義的類型。您可以使用用戶定義表類型為存儲過程或函數聲明表值參數,或者聲明您要在批處理中或在存儲過程或函數的主體中使用的表變量。
??若要創建用戶定義表類型,請使用CREATE TYPE語句。為了確保用戶定義表類型的數據滿足特定要求,您可以對用戶定義表類型創建唯一約束和主鍵。
??用戶定義表類型具有下列限制:
- 用戶定義表類型不能用作表中的列或結構化用戶定義類型中的字段。
- 基于用戶定義表類型的別名類型(詳見CREATE TYPE語句)
- [NOT FOR REPLICATION] 選項是不允許的。
- CHECK 約束要求保留計算列。
- 計算列的主鍵必須是 PERSISTED 和 NOT NULL。
- 無法對用戶定義表類型創建非聚集索引,除非該索引是對用戶定義表類型創建 PRIMARY KEY 或 UNIQUE 約束的結果。(SQL Server 使用索引強制實施任何 UNIQUE 或 PRIMARY KEY 約束。)
- 在創建用戶定義表類型定義后不能對其進行修改。
- 不能在用戶定義表類型的計算列的定義中調用用戶定義函數。
【示例】
(1)定義用戶表值參數
USE AdventureWorks2008R2;
GO
/* Create a user-defined table type */
CREATE TYPE LocationTableType AS TABLE
( LocationName VARCHAR(50)
, CostRate INT );
GO
(2)下面的示例使用 Transact-SQL 并演示如何執行以下操作:創建表值參數類型,聲明變量來引用它,填充參數列表,然后將值傳遞到存儲過程。
USE AdventureWorks2008R2;
GO
/* Create a table type. */
CREATE TYPE LocationTableType AS TABLE
( LocationName VARCHAR(50),
CostRate INT )
GO
/* Create a procedure to receive data for the table-valued parameter. */
CREATE PROCEDURE usp_InsertProductionLocation
@TVP LocationTableType READONLY
AS
SET NOCOUNT ON
INSERT INTO AdventureWorks2008R2.Production.Location
(Name,
CostRate,
Availability,
ModifiedDate)
SELECT *, 0, GETDATE()
FROM @TVP;
GO
/* Declare a variable that references the type. */
DECLARE @LocationTVP AS LocationTableType;
/* Add data to the table variable. */
INSERT INTO @LocationTVP (LocationName, CostRate)
SELECT Name, 0.00
FROM AdventureWorks2008R2.Person.StateProvince;
/* Pass the table variable data to a stored procedure. */
EXEC usp_InsertProductionLocation @LocationTVP;
GO
(3)
CREATE TYPE SalesByStore_tbl AS TABLE
(titleid varchar(80) NOT NULL PRIMARY KEY,
qty smallint NOT NULL)
go
CREATE PROCEDURE SalesByStore @storeid varchar(30) AS
DECLARE @ret SalesByStore_tbl
INSERT @ret (titleid, qty)
SELECT t.titleid, s.store_id
FROM sales s
JOIN titles t ON t.titleid = s.titleid
WHERE s.store_id = @storeid
SELECT * FROM @ret
go
CREATE PROCEDURE BigSalesByStore @storeid varchar(30),
@qty smallint AS
DECLARE @data SalesByStore_tbl
INSERT @data
EXEC SalesByStore @storeid
SELECT titleid, qty FROM @data WHERE qty>= @qty
go
EXEC SalesByStore '7131'
EXEC BigSalesByStore '7131', 25
go
DROP PROCEDURE SalesByStore, BigSalesByStore
DROP TYPE SalesByStore_tbl
表值參數與 BULK INSERT 操作
表值參數的使用方法與其他基于數據集的變量的使用方法相似,但是,頻繁使用表值參數將比大型數據集要快。大容量操作的啟動開銷比表值參數大,與之相比,表值參數在插入數目少于 1000 的行時具有很好的執行性能。
??重用的表值參數可從臨時表緩存中受益。這一表緩存功能可比對等的 BULK INSERT 操作提供更好的伸縮性。使用小型行插入操作時,可以通過使用參數列表或批量語句(而不是 BULK INSERT 操作或表值參數)來獲得小的性能改進。但是,這些方法在編程上不太方便,并且隨著行的增加,性能會迅速下降。
??表值參數在執行性能上與對等的參數陣列實現相當甚至更好。下表說明根據插入操作的速度應使用哪種技術。