資料表 (Transact-SQL)

這是可用來儲存結果集以便稍後進行處理的特殊資料類型。table 主要用於暫時儲存當做資料表值函式結果集傳回的一組資料列。函數和變數可以宣告成 table 類型。在函數、預存程序和批次中,可以使用 table 變數。若要宣告 table 類型的變數,請使用 DECLARE @local_variable

主題連結圖示Transact-SQL 語法慣例

語法


table_type_definition ::= 
    TABLE ( { <column_definition> | <table_constraint> } [ ,...n ] ) 

<column_definition> ::= 
    column_name scalar_data_type 
    [ COLLATE <collation_definition> ] 
    [ [ DEFAULT constant_expression ] | IDENTITY [ ( seed , increment ) ] ] 
    [ ROWGUIDCOL ] 
    [ column_constraint ] [ ...n ] 

<column_constraint> ::= 
    { [ NULL | NOT NULL ] 
    | [ PRIMARY KEY | UNIQUE ] 
    | CHECK ( logical_expression ) 
    } 

<table_constraint> ::= 
     { { PRIMARY KEY | UNIQUE } ( column_name [ ,...n ] )
     | CHECK ( logical_expression ) 
     } 

引數

  • table_type_definition
    這是在 CREATE TABLE 中,用來定義資料表的相同資訊子集。資料表宣告包括資料行定義、名稱、資料類型和條件約束。允許使用的條件約束類型只有 PRIMARY KEY、UNIQUE KEY 和 NULL。

    如需有關語法的詳細資訊,請參閱<CREATE TABLE (Transact-SQL)>、<CREATE FUNCTION (Transact-SQL)>和<DECLARE @local_variable (Transact-SQL)>。

  • collation_definition
    這是 Microsoft Windows 地區設定和比較樣式、Windows 地區設定和二進位標記法所組成之資料行的定序,或 Microsoft SQL Server 定序。若未指定 collation_definition,資料行就會繼承目前資料庫的定序。如果將資料行定義為 Common Language Runtime (CLR) 使用者定義類型,資料行便會繼承使用者定義類型的定序。

最佳作法

請勿使用資料表變數來儲存大量資料 (超過 100 個資料列)。當資料表變數包含大量資料時,計畫選擇可能不是最佳或穩定的方式。請考慮將這類查詢重寫成使用暫存資料表或使用 USE PLAN 查詢提示,確保最佳化工具針對您的案例使用適當的現有查詢計畫。

一般備註

批次之 FROM 子句中的名稱可以依照下列範例來參考 table 變數:

SELECT Employee_ID, Department_ID FROM @MyTableVar;

在 FROM 子句之外,您必須依照下列範例所示,利用別名來參考 table 變數:

SELECT EmployeeID, DepartmentID 
FROM @MyTableVar m
JOIN Employee on (m.EmployeeID =Employee.EmployeeID AND
   m.DepartmentID = Employee.DepartmentID);

若為查詢計畫不變更的小規模查詢,而且以重新編譯考量為主時,table 變數可提供下列優點:

  • table 變數的行為類似於區域變數。它有一個定義妥善的範圍。這是其宣告所在的函數、預存程序或批次。

    在 table 變數的範圍內,您可以依照正規資料表的方式來使用它。在 SELECT、INSERT、UPDATE 和 DELETE 陳述式中,任何使用資料表或資料表運算式的位置都可以套用它。不過在下列陳述式中,不能使用 table:

    SELECT select_list INTO table_variable;
    

    在定義 table 變數的函數、預存程序或批次結束時,會自動清除該變數。

  • 沒有影響效能的成本考量選擇時,預存程序所用之 table 變數所造成的預存程序重新編譯,比使用暫存資料表時還少。

  • 包含 table 變數的交易,只會在 table 變數更新期間持續存在。因此,table 變數比較不需要鎖定和記錄資源。

限制事項

SQL Server 最佳化工具的成本考量推論模型不支援 table 變數。因此,需要成本考量選擇來達成有效率的查詢計畫時,就不應該使用這些變數。需要成本考量選擇時,最好使用暫存資料表。這種資料表通常會包含具有聯結的查詢、平行處理原則決定,以及索引選取範圍選擇。

修改 table 變數的查詢不會產生平行查詢執行計畫。修改非常大的 table 變數或複雜查詢中的 table 變數時,可能會影響效能。在這些狀況中,請改用暫存資料表。如需詳細資訊,請參閱<CREATE TABLE (Transact-SQL)>。讀取但不修改 table 變數的查詢仍然可以平行處理。

您無法明確建立 table 變數的索引,也無法保留 table 變數的任何統計資料。在某些情況下,改用支援索引和統計資料的暫存資料表可以改進效能。如需有關暫存資料表的詳細資訊,請參閱<CREATE TABLE (Transact-SQL)>。

table 類型宣告中的 CHECK 條件約束、DEFAULT 值和計算資料行無法呼叫使用者定義函數。

不支援 table 變數之間的指派作業。

由於 table 變數的範圍受到限制,且不是保存資料庫的一部分,因此,它們不會受交易回復的影響。

範例

A. 宣告資料表類型的變數

下列範例會建立一個 table 變數來儲存 UPDATE 陳述式的 OUTPUT 子句所指定的值。之後的兩個 SELECT 陳述式會傳回 @MyTableVar 中的值,以及 Employee 資料表中更新作業的結果。請注意,INSERTED.ModifiedDate 資料行中的結果不同於 Employee 資料表中 ModifiedDate 資料行的值。這是因為將 ModifiedDate 值更新成目前日期的 AFTER UPDATE 觸發程序是定義在 Employee 資料表上。不過,從 OUTPUT 傳回的資料行會反映引發觸發程序之前的資料。如需詳細資訊,請參閱<OUTPUT 子句 (Transact-SQL)>。

USE AdventureWorks2008R2;
GO
DECLARE @MyTableVar table(
    EmpID int NOT NULL,
    OldVacationHours int,
    NewVacationHours int,
    ModifiedDate datetime);
UPDATE TOP (10) HumanResources.Employee
SET VacationHours = VacationHours * 1.25,
    ModifiedDate = GETDATE() 
OUTPUT inserted.BusinessEntityID,
       deleted.VacationHours,
       inserted.VacationHours,
       inserted.ModifiedDate
INTO @MyTableVar;
--Display the result set of the table variable.
SELECT EmpID, OldVacationHours, NewVacationHours, ModifiedDate
FROM @MyTableVar;
GO
--Display the result set of the table.
SELECT TOP (10) BusinessEntityID, VacationHours, ModifiedDate
FROM HumanResources.Employee;
GO

B. 建立嵌入資料表值函式

下列範例傳回嵌入資料表值函式。它會傳回三個資料行:ProductID、Name,以及年初至今賣給商店之每項產品的總計彙總 YTD Total (依商店區分)。

USE AdventureWorks2008R2;
GO
IF OBJECT_ID (N'Sales.ufn_SalesByStore', N'IF') IS NOT NULL
    DROP FUNCTION Sales.ufn_SalesByStore;
GO
CREATE FUNCTION Sales.ufn_SalesByStore (@storeid int)
RETURNS TABLE
AS
RETURN 
(
    SELECT P.ProductID, P.Name, SUM(SD.LineTotal) AS 'Total'
    FROM Production.Product AS P 
    JOIN Sales.SalesOrderDetail AS SD ON SD.ProductID = P.ProductID
    JOIN Sales.SalesOrderHeader AS SH ON SH.SalesOrderID = SD.SalesOrderID
    JOIN Sales.Customer AS C ON SH.CustomerID = C.CustomerID
    WHERE C.StoreID = @storeid
    GROUP BY P.ProductID, P.Name
);
GO

若要叫用函數,請執行這項查詢。

SELECT * FROM Sales.ufn_SalesByStore (602);