共用方式為


OUTPUT 子句 (Transact-SQL)

適用於:SQL Server Azure SQL 資料庫 Azure SQL 受控執行個體

根據 、、 DELETEMERGE 語句所影響INSERTUPDATE的每個數據列,從 或表達式傳回資訊。 這些結果可以傳回給負責處理的應用程式,以便用在確認訊息、封存或其他這類應用程式需求等用途上。 這些結果也可以插入資料表或資料表變數中。 此外,您可以在巢狀 、、 DELETEMERGE 語句中擷取 子句的結果OUTPUT,並將這些結果插入目標數據表或UPDATE檢視中。INSERT

注意

具有 UPDATE子句的 OUTPUTINSERTDELETE 語句會傳回數據列給用戶端,即使語句發生錯誤且回復也一樣。 當您執行 語句時發生任何錯誤時,不應該使用結果。

用於:

Transact-SQL 語法慣例

語法

<OUTPUT_CLAUSE> ::=
{
    [ OUTPUT <dml_select_list> INTO { @table_variable | output_table } [ ( column_list ) ] ]
    [ OUTPUT <dml_select_list> ]
}
<dml_select_list> ::=
{ <column_name> | scalar_expression } [ [ AS ] column_alias_identifier ]
    [ , ...n ]

<column_name> ::=
{ DELETED | INSERTED | from_table_name } . { * | column_name }
    | $action

引數

@table_variable

指定 table 變數以將傳回的資料列插入其中,而不傳回給呼叫端。 @table_variable必須在 、 UPDATEDELETEMERGE 語句之前INSERT宣告。

如果未 指定column_list數據表 變數必須具有與結果集相同的數據行數目 OUTPUT 。 識別和計算資料行例外,它們必須被略過。 如果指定 column_list,任何省略的資料行都必須允許 Null 值或已具有指派的預設值。

如需數據表變數的詳細資訊,請參閱 table

output_table

指定資料表,讓傳回的資料列插入其中,而不要傳回給呼叫端。 output_table可能是臨時表。

如果未 指定column_list ,數據表的數據行數目 OUTPUT 必須與結果集相同。 識別和計算資料行例外,它們必須被略過。 如果指定 column_list,任何省略的資料行都必須允許 Null 值或已具有指派的預設值。

output_table無法:

  • 啟用它所定義的觸發程序。
  • 參與條件約束的任一 FOREIGN KEY 端。
  • 具有 CHECK 條件約束或啟用的規則。

column_list

子句目標數據表 INTO 上的選擇性數據行名稱清單。 這類似於 INSERT 語句中允許的數據行清單。

scalar_expression

評估為單一值的符號和運算子的任何組合。 scalar_expression中不允許聚合函數。

要修改之數據表中數據行的任何參考都必須以 或 DELETED 前置詞INSERTED限定。

column_alias_identifier

用來參考數據行名稱的替代名稱。

DELETED

數據行前置詞,指定更新或刪除作業所刪除的值,以及任何未隨著目前作業變更的現有值。 前面加上的數據DELETED行會反映、 DELETEMERGE 語句完成之前UPDATE的值。

DELETED無法與語句中的 INSERT 子句搭配OUTPUT使用。

INSERTED

數據行前置詞,指定插入或更新作業所新增的值,以及任何未隨著目前作業變更的現有值。 前面加上 INSERTED 的數據行會反映 、 INSERTMERGE 語句完成之後UPDATE的值,但在執行觸發程式之前。

INSERTED無法與語句中的 DELETE 子句搭配OUTPUT使用。

from_table_name

數據行前置詞,指定要更新或刪除之數據列的DELETEUPDATEMERGE 語句子句中包含的FROM數據表。

如果子句中也指定了要修改的 FROM 數據表,該數據表中數據行的任何參考都必須以 INSERTEDDELETED 前置詞限定。

*

星號 (*) 會指定受刪除、插入或更新動作影響的所有數據行都會依照資料表中存在的順序傳回。

例如,在下列DELETE語句中,OUTPUT DELETED.*會傳回從ShoppingCartItem數據表中刪除的所有數據行:

DELETE Sales.ShoppingCartItem
    OUTPUT DELETED.*;

column_name

明確的數據行參考。 修改之數據表的任何參考都必須適當地由 INSERTEDDELETED 前置詞正確限定,例如: INSERTED.<column_name>

$action

僅適用於 MERGE 語句。 在語句中OUTPUTMERGE指定 nvarchar(10) 類型的數據行,根據在該數據列上執行的動作,傳回每個數據列三個值的其中一個:INSERTUPDATEDELETE

備註

OUTPUT <dml_select_list>子句和 OUTPUT <dml_select_list> INTO { @table_variable | output_table } 子句可以在單INSERT一 、、 UPDATEDELETEMERGE 語句中定義。

注意

除非另有指定,否則子句的 OUTPUT 參考會同時參考 OUTPUT 子句和 OUTPUT INTO 子句。

OUTPUT句在 或 UPDATE 作業之後INSERT擷取識別或計算數據行的值可能很有用。

當計算數據列包含在 中 <dml_select_list>時,輸出數據表或數據表變數中的對應數據行不是計算數據行。 新資料行中的值是執行陳述式時所計算的值。

變更套用至數據表的順序,以及數據列插入輸出數據表或數據表變數的順序,不保證對應。

如果參數或變數修改為語句的一 UPDATE 部分, OUTPUT 子句一律會傳回參數或變數的值,如同語句執行前的值,而不是修改的值。

您可以在OUTPUTUPDATE使用WHERE CURRENT OF語法的數據指標上使用 或 DELETE 語句。

下列語句不支援 子 OUTPUT 句:

  • 參考本機資料分割檢視、分散式資料分割檢視或遠端資料表的 DML 陳述式。

  • INSERT 包含語句的 EXECUTE 語句。

  • 當資料庫相容性層級設定為 100 時,子句中不允許 OUTPUT 全文檢索述詞。

  • OUTPUT INTO子句無法用來插入檢視或數據列集函式。

  • 如果使用者定義函數包含 OUTPUT INTO 具有數據表做為其目標的子句,則無法建立。

若要防止非決定性行為, OUTPUT 子句不能包含下列參考:

  • 執行使用者或系統資料存取或假設會執行這類存取的子查詢或使用者定義函數。 如果未系結架構,則會假設使用者定義函式會執行數據存取。

  • 當檢視表或嵌入資料表值函式中的資料行是由下列其中一種方法所定義時:

    • 子查詢。

    • 執行使用者或系統資料存取的使用者定義函數,或假設會執行這類存取的使用者定義函數。

    • 包含使用者定義函數的計算資料行,而該函數會在其定義中執行使用者或系統資料存取。

    當 SQL Server 在 子句中 OUTPUT 偵測到這類數據行時,就會引發錯誤 4186。

將數據從 OUTPUT 子句傳回的數據插入數據表

當您在巢狀 、、 DELETEMERGE 語句中擷取 子句的結果OUTPUT,並將這些結果插入目標數據表時,UPDATE請記住下列資訊:INSERT

  • 整個作業是不可部分完成的。 INSERT語句和包含 OUTPUT 子句執行的巢狀 DML 語句,或整個語句失敗。

  • 下列限制適用於外部 INSERT 語句的目標:

    • 目標不能是遠端數據表、檢視表或通用數據表運算式。

    • 目標不能有 FOREIGN KEY 條件約束,或由 FOREIGN KEY 條件約束參考。

    • 無法在目標上定義觸發程式。

    • 目標無法參與事務複製的合併式複寫或可更新的訂閱。

  • 下列限制適用於巢狀 DML 陳述式:

    • 目標不能是遠端數據表或數據分割檢視。

    • 來源本身不能包含 <dml_table_source> 子句。

  • 包含子句的語句<dml_table_source>不支援 INSERTOUTPUT INTO句。

  • @@ROWCOUNT 只會傳回外部 INSERT 語句所插入的數據列。

  • @@IDENTITYSCOPE_IDENTITY和會 IDENT_CURRENT 傳回只由巢狀 DML 語句產生的識別值,而不是外部 INSERT 語句所產生的值。

  • 查詢通知會將語句視為單一實體,而且所建立的任何訊息類型都是巢狀 DML 的類型,即使重大變更來自外部 INSERT 語句本身也一樣。

  • 在 子句中 <dml_table_source>SELECTWHERE 子句不能包含子查詢、聚合函數、排名函數、全文檢索述詞、執行數據存取的使用者定義函式或函 TEXTPTR() 式。

平行處理原則

OUTPUT 結果傳回給客戶端或數據表變數的子句,一律會使用序列計劃。

在設定為相容性層級 130 或更高版本的資料庫內容中,如果 INSERT...SELECT 作業使用 WITH (TABLOCK) 語句的提示 SELECT ,也會使用 OUTPUT...INTO 插入暫存或用戶數據表,則 的目標數據表 INSERT...SELECT 會根據子樹成本而符合平行處理原則的資格。 子句中所 OUTPUT INTO 參考的目標數據表不符合平行處理原則的資格。

觸發程序

OUTPUT 傳回的數據行會反映在 、 UPDATEDELETE 語句完成之後INSERT的數據,但在執行觸發程式之前。

針對INSTEAD OF觸發程式,即使觸發程式作業的結果沒有進行任何修改,也會產生傳回的結果,INSERTUPDATE就好像 、 或 DELETE 已實際發生一樣。 如果在觸發程式主體內使用包含 OUTPUT 子句的語句,則必須使用數據表別名來參考插入和刪除的觸發程式,以避免與相關聯的 OUTPUTDELETED 數據表重複數據行參考INSERTED

如果指定 子 OUTPUT 句而不指定 INTO 關鍵詞,DML 作業的目標就無法針對指定的 DML 動作定義任何已啟用的觸發程式。 例如,如果 OUTPUT 子句是在語句中 UPDATE 定義,則目標數據表不能有任何啟用的 UPDATE 觸發程式。

sp_configure如果已設定選項不允許觸發程式的結果,OUTPUT沒有 INTO 子句的 子句會導致語句在觸發程式內叫用時失敗。

資料類型

OUTPUT句支援大型對象數據類型:nvarchar(max)varchar(max)、varbinary(max)textntextimagexml。 當您在 語句中使用 .WRITE UPDATE 子句來修改 nvarchar(max)varchar(max)varbinary(max) 數據行時,如果參考值影像之前和之後,就會傳回完整的值。 函TEXTPTR()式無法在 子句中的 textntextimage 數據行上顯示為表達式的OUTPUT部分。

佇列

您可以在 OUTPUT 使用資料表做為佇列的應用程式中使用 ,或用來保存中繼結果集。 也就是說,應用程式會不斷新增或移除資料表的資料列。 下列範例會使用 OUTPUT 語句中的 DELETE 子句,將已刪除的數據列傳回至呼叫的應用程式。

USE AdventureWorks2022;
GO

DELETE TOP(1) dbo.DatabaseLog WITH (READPAST)
OUTPUT DELETED.*
WHERE DatabaseLogID = 7;
GO

這個範例會以單一動作從用作佇列的資料表中移除資料列,再將刪除的值傳回負責處理的應用程式。 您也可以實作其他語意,例如使用數據表來實作堆疊。 不過,SQL Server 並不保證 DML 語句使用 OUTPUT 子句處理和傳回數據列的順序。 應用程式必須包含可保證所需語意的適當 WHERE 子句,或了解當多個數據列可能符合 DML 作業資格時,就不會有保證的順序。 下列範例會使用子查詢,且假設唯一性是 DatabaseLogID 資料行的特性,以便實作所需要的排序語意。

USE tempdb;
GO

CREATE TABLE dbo.table1
(
    id INT,
    employee VARCHAR(32)
);
GO

INSERT INTO dbo.table1
VALUES (1, 'Fred'),
    (2, 'Tom'),
    (3, 'Sally'),
    (4, 'Alice');
GO

DECLARE @MyTableVar TABLE (
    id INT,
    employee VARCHAR(32)
);

PRINT 'table1, before delete';

SELECT *
FROM dbo.table1;

DELETE
FROM dbo.table1
OUTPUT DELETED.*
INTO @MyTableVar
WHERE id = 4
    OR id = 2;

PRINT 'table1, after delete';

SELECT *
FROM dbo.table1;

PRINT '@MyTableVar, after delete';

SELECT *
FROM @MyTableVar;

DROP TABLE dbo.table1;

以下是結果:

table1, before delete
id          employee
----------- ------------------------------
1           Fred
2           Tom
3           Sally
4           Alice

table1, after delete
id          employee
----------- ------------------------------
1           Fred
3           Sally

@MyTableVar, after delete
id          employee
----------- ------------------------------
2           Tom
4           Alice

注意

READPAST如果您的案例允許多個應用程式執行一個數據表的破壞性讀取,請使用 和 DELETE 語句中的UPDATE數據表提示。 這可以防止當另一個應用程式已在讀取資料表中第一個符合的記錄時,所可能出現的鎖定問題。

權限

SELECT 擷取 <dml_select_list> 或用於 <scalar_expression>的任何數據行都需要許可權。

INSERT 在中指定的 <output_table>任何數據表上都需要許可權。

範例

本文 Transact-SQL 程式碼範例使用 AdventureWorks2022AdventureWorksDW2022 範例資料庫,從 Microsoft SQL Server Samples 和 Community Projects (Microsoft SQL Server 範例和社群專案)首頁即可下載。

A. 搭配 INSERT 語句使用 OUTPUT INTO

下列範例會將資料列插入 ScrapReason 資料表中,並且利用 OUTPUT 子句,將陳述式的結果傳回 @MyTableVar 資料表變數。 由於數據 ScrapReasonID 行是以 IDENTITY 屬性定義,因此該數據行的 INSERT 語句中未指定值。 不過,該數據行之 資料庫引擎 所產生的值會在 數據行 的 INSERTED.ScrapReasonID子句中OUTPUT傳回。

USE AdventureWorks2022;
GO

DECLARE @MyTableVar TABLE (
    NewScrapReasonID SMALLINT,
    Name VARCHAR(50),
    ModifiedDate DATETIME
);

INSERT Production.ScrapReason
    OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
        INTO @MyTableVar
VALUES (N'Operator error', GETDATE());

--Display the result set of the table variable.
SELECT NewScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
--Display the result set of the table.
SELECT ScrapReasonID, Name, ModifiedDate
FROM Production.ScrapReason;
GO

B. 搭配 DELETE 語句使用 OUTPUT

下列範例會刪除 ShoppingCartItem 資料表中的所有資料列。 子句 OUTPUT DELETED.* 會指定語句的結果 DELETE ,也就是已刪除數據列中的所有數據行都會傳回給呼叫的應用程式。 後面的 SELECT 陳述式會驗證 ShoppingCartItem 資料表刪除作業的結果。

USE AdventureWorks2022;
GO

DELETE Sales.ShoppingCartItem
OUTPUT DELETED.*
WHERE ShoppingCartID = 20621;

--Verify the rows in the table matching the WHERE clause have been deleted.
SELECT COUNT(*) AS [Rows in Table] FROM Sales.ShoppingCartItem WHERE ShoppingCartID = 20621;
GO

C. 搭配 UPDATE 語句使用 OUTPUT INTO

下列範例會將 VacationHours 資料表前 10 個資料列的 Employee 資料行更新 25%。 OUTPUT 子句會將在 DELETED.VacationHours 資料行中套用 UPDATE 陳述式之前便已存在的 VacationHours 值,以及 INSERTED.VacationHours 資料行中更新的值傳回給 @MyTableVar 資料表變數。

接下來有兩個 SELECT 語句,傳回 中的 @MyTableVar 值,以及數據表中 Employee 更新作業的結果。

USE AdventureWorks2022;
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

D. 使用 OUTPUT INTO 傳回表達式

下列範例是以範例 C 為基礎所建立,它在 OUTPUT 子句中定義一個運算式,當做更新的 VacationHours 值和套用更新之前的 VacationHours 值之間的差異。 此運算式的值會傳回給 VacationHoursDifference 資料行中的 @MyTableVar 資料表變數。

USE AdventureWorks2022;
GO

DECLARE @MyTableVar TABLE (
    EmpID INT NOT NULL,
    OldVacationHours INT,
    NewVacationHours INT,
    VacationHoursDifference INT,
    ModifiedDate DATETIME);

UPDATE TOP (10) HumanResources.Employee
SET VacationHours = VacationHours * 1.25,
    ModifiedDate = GETDATE()
OUTPUT INSERTED.BusinessEntityID,
       DELETED.VacationHours,
       INSERTED.VacationHours,
       INSERTED.VacationHours - DELETED.VacationHours,
       INSERTED.ModifiedDate
INTO @MyTableVar;

--Display the result set of the table variable.
SELECT EmpID, OldVacationHours, NewVacationHours,
    VacationHoursDifference, ModifiedDate
FROM @MyTableVar;
GO
SELECT TOP (10) BusinessEntityID, VacationHours, ModifiedDate
FROM HumanResources.Employee;
GO

E. 在 UPDATE 語句中搭配from_table_name使用 OUTPUT INTO

下列範例會針對具有指定 ProductIDScrapReasonID 的所有工單,更新 WorkOrder 資料表中的 ScrapReasonID 資料行。 OUTPUT INTO 子句會從更新的資料表 (WorkOrder) 傳回值,也會從 Product 傳回值。 Product 子句利用 FROM 資料表來指定要更新的資料列。 由於 WorkOrder 資料表定義了 AFTER UPDATE 觸發程序,因此,需要 INTO 關鍵字。

USE AdventureWorks2022;
GO

DECLARE @MyTestVar TABLE (
    OldScrapReasonID INT NOT NULL,
    NewScrapReasonID INT NOT NULL,
    WorkOrderID INT NOT NULL,
    ProductID INT NOT NULL,
    ProductName NVARCHAR(50)NOT NULL);

UPDATE Production.WorkOrder
SET ScrapReasonID = 4
OUTPUT DELETED.ScrapReasonID,
       INSERTED.ScrapReasonID,
       INSERTED.WorkOrderID,
       INSERTED.ProductID,
       p.Name
    INTO @MyTestVar
FROM Production.WorkOrder AS wo
    INNER JOIN Production.Product AS p
    ON wo.ProductID = p.ProductID
    AND wo.ScrapReasonID= 16
    AND p.ProductID = 733;

SELECT OldScrapReasonID, NewScrapReasonID, WorkOrderID,
    ProductID, ProductName
FROM @MyTestVar;
GO

F. 在 DELETE 語句中搭配from_table_name使用 OUTPUT INTO

下列範例根據 ProductProductPhoto 陳述式的 FROM 子句所定義的搜尋準則,來刪除 DELETE 資料表中的資料列。 OUTPUT 子句會傳回所刪除的資料表資料行 (DELETED.ProductIDDELETED.ProductPhotoID) 及 Product 資料表中的資料行。 FROM 子句利用這份資料表來指定要刪除的資料列。

USE AdventureWorks2022;
GO

DECLARE @MyTableVar TABLE (
    ProductID INT NOT NULL,
    ProductName NVARCHAR(50)NOT NULL,
    ProductModelID INT NOT NULL,
    PhotoID INT NOT NULL);

DELETE Production.ProductProductPhoto
OUTPUT DELETED.ProductID,
       p.Name,
       p.ProductModelID,
       DELETED.ProductPhotoID
    INTO @MyTableVar
FROM Production.ProductProductPhoto AS ph
JOIN Production.Product as p
    ON ph.ProductID = p.ProductID
    WHERE p.ProductModelID BETWEEN 120 and 130;

--Display the results of the table variable.
SELECT ProductID, ProductName, ProductModelID, PhotoID
FROM @MyTableVar
ORDER BY ProductModelID;
GO

G. 搭配大型物件數據類型使用 OUTPUT INTO

下列範例會使用 .WRITE 子句,更新 數據表中 nvarchar(max) 數據行中的Production.DocumentDocumentSummary部分值。 components 一字藉由指定用來取代的文字、現有資料中要被取代之文字的起始位置 (位移),以及要取代的字元數 (長度) 來取代為 features 一字。 此範例會使用 OUTPUT 子句,將 DocumentSummary 資料行的前後影像傳回給 @MyTableVar 資料表變數。 傳回資料行影像前後的完整 DocumentSummary

USE AdventureWorks2022;
GO

DECLARE @MyTableVar TABLE (
    SummaryBefore NVARCHAR(MAX),
    SummaryAfter NVARCHAR(MAX)
);

UPDATE Production.Document
SET DocumentSummary.WRITE(N'features', 28, 10)
OUTPUT DELETED.DocumentSummary,
       INSERTED.DocumentSummary
    INTO @MyTableVar
WHERE Title = N'Front Reflector Bracket Installation';

SELECT SummaryBefore, SummaryAfter
FROM @MyTableVar;
GO

H. 在 INSTEAD OF 觸發程式中使用 OUTPUT

下列範例會利用觸發程序中的 OUTPUT 子句來傳回觸發程序作業的結果。 首先在 ScrapReason 資料表上建立檢視,然後在此檢視上定義 INSTEAD OF INSERT 觸發程序,只讓使用者修改基底資料表的 Name 資料行。 由於 ScrapReasonID 資料行是基底資料表中的 IDENTITY 資料行,觸發程序會忽略使用者提供的值。 這會使資料庫引擎自動產生正確的值。 另外,使用者提供的 ModifiedDate 值會被忽略,且會設為目前的日期。 OUTPUT 子句會傳回實際插入 ScrapReason 資料表的值。

USE AdventureWorks2022;
GO

IF OBJECT_ID('dbo.vw_ScrapReason', 'V') IS NOT NULL
    DROP VIEW dbo.vw_ScrapReason;
GO

CREATE VIEW dbo.vw_ScrapReason
AS
SELECT ScrapReasonID,
    Name,
    ModifiedDate
FROM Production.ScrapReason;
GO

CREATE TRIGGER dbo.io_ScrapReason ON dbo.vw_ScrapReason
INSTEAD OF INSERT
AS
BEGIN
    --ScrapReasonID is not specified in the list of columns to be inserted
    --because it is an IDENTITY column.
    INSERT INTO Production.ScrapReason (
        Name,
        ModifiedDate
    )
    OUTPUT INSERTED.ScrapReasonID,
        INSERTED.Name,
        INSERTED.ModifiedDate
    SELECT Name, GETDATE()
    FROM INSERTED;
END
GO

INSERT vw_ScrapReason (
    ScrapReasonID,
    Name,
    ModifiedDate
)
VALUES (
    99,
    N'My scrap reason',
    '20030404'
);
GO

以下是 2004 年 4 月 12 日 ('2004-04-12') 所產生的結果集。 ScrapReasonIDActualModifiedDate 數據行會反映觸發程式作業所產生的值,而不是語句中INSERT提供的值。

ScrapReasonID  Name             ModifiedDate
-------------  ---------------- -----------------------
17             My scrap reason  2004-04-12 16:23:33.050

I. 搭配身分識別和計算數據行使用 OUTPUT INTO

下列範例會建立 EmployeeSales 資料表,之後再利用含有 INSERT 陳述式的 SELECT 陳述式來擷取來源資料表中的資料,以插入幾個資料列。 EmployeeSales 資料表包含一個識別欄位 (EmployeeID) 和一個計算資料行 (ProjectedSales)。

USE AdventureWorks2022;
GO

IF OBJECT_ID('dbo.EmployeeSales', 'U') IS NOT NULL
    DROP TABLE dbo.EmployeeSales;
GO

CREATE TABLE dbo.EmployeeSales (
    EmployeeID INT IDENTITY(1, 5) NOT NULL,
    LastName NVARCHAR(20) NOT NULL,
    FirstName NVARCHAR(20) NOT NULL,
    CurrentSales MONEY NOT NULL,
    ProjectedSales AS CurrentSales * 1.10
);
GO

DECLARE @MyTableVar TABLE (
    EmployeeID INT NOT NULL,
    LastName NVARCHAR(20) NOT NULL,
    FirstName NVARCHAR(20) NOT NULL,
    CurrentSales MONEY NOT NULL,
    ProjectedSales MONEY NOT NULL
);

INSERT INTO dbo.EmployeeSales (
    LastName,
    FirstName,
    CurrentSales
)
OUTPUT INSERTED.EmployeeID,
    INSERTED.LastName,
    INSERTED.FirstName,
    INSERTED.CurrentSales,
    INSERTED.ProjectedSales
INTO @MyTableVar
SELECT c.LastName,
    c.FirstName,
    sp.SalesYTD
FROM Sales.SalesPerson AS sp
INNER JOIN Person.Person AS c
    ON sp.BusinessEntityID = c.BusinessEntityID
WHERE sp.BusinessEntityID LIKE '2%'
ORDER BY c.LastName,
    c.FirstName;

SELECT EmployeeID,
    LastName,
    FirstName,
    CurrentSales,
    ProjectedSales
FROM @MyTableVar;
GO

SELECT EmployeeID,
    LastName,
    FirstName,
    CurrentSales,
    ProjectedSales
FROM dbo.EmployeeSales;
GO

J. 在單一語句中使用 OUTPUT 和 OUTPUT INTO

下列範例根據 ProductProductPhoto 陳述式的 FROM 子句所定義的搜尋準則,來刪除 DELETE 資料表中的資料列。 OUTPUT INTO 子句會將所要刪除之資料表中的資料行 (DELETED.ProductIDDELETED.ProductPhotoID) 及 Product 資料表中的資料行傳回給 @MyTableVar 資料表變數。 Product 子句利用 FROM 資料表來指定要刪除的資料列。 子句會將 OUTPUT DELETED.ProductIDDELETED.ProductPhotoID 數據行和數據列從 ProductProductPhoto 數據表中刪除的日期和時間傳回至呼叫的應用程式。

USE AdventureWorks2022;
GO

DECLARE @MyTableVar TABLE (
    ProductID INT NOT NULL,
    ProductName NVARCHAR(50) NOT NULL,
    ProductModelID INT NOT NULL,
    PhotoID INT NOT NULL
);

DELETE Production.ProductProductPhoto
OUTPUT DELETED.ProductID,
    p.Name,
    p.ProductModelID,
    DELETED.ProductPhotoID
INTO @MyTableVar
OUTPUT DELETED.ProductID,
    DELETED.ProductPhotoID,
    GETDATE() AS DeletedDate
FROM Production.ProductProductPhoto AS ph
INNER JOIN Production.Product AS p
    ON ph.ProductID = p.ProductID
WHERE p.ProductID BETWEEN 800
        AND 810;

--Display the results of the table variable.
SELECT ProductID,
    ProductName,
    PhotoID,
    ProductModelID
FROM @MyTableVar;
GO

K. 插入從 OUTPUT 子句傳回的數據

下列範例將擷取從 OUTPUT 陳述式的 MERGE 子句中傳回的資料,並將該資料插入另一個資料表中。 MERGE 陳述式會根據在 Quantity 資料表中處理的順序,每天更新 ProductInventory 資料表的 SalesOrderDetail 資料行。 它也會刪除庫存下降至 0 或減少的產品數據列。 此範例會擷取已刪除的資料列,並將其插入另一個資料表 ZeroInventory,該資料表會追蹤沒有存貨的產品。

USE AdventureWorks2022;
GO

IF OBJECT_ID(N'Production.ZeroInventory', N'U') IS NOT NULL
    DROP TABLE Production.ZeroInventory;
GO

--Create ZeroInventory table.
CREATE TABLE Production.ZeroInventory (
    DeletedProductID INT,
    RemovedOnDate DATETIME
    );
GO

INSERT INTO Production.ZeroInventory (
    DeletedProductID,
    RemovedOnDate
)
SELECT ProductID,
    GETDATE()
FROM (
    MERGE Production.ProductInventory AS pi
    USING (
        SELECT ProductID,
            SUM(OrderQty)
        FROM Sales.SalesOrderDetail AS sod
        INNER JOIN Sales.SalesOrderHeader AS soh
            ON sod.SalesOrderID = soh.SalesOrderID
                AND soh.OrderDate = '20070401'
        GROUP BY ProductID
        ) AS src(ProductID, OrderQty)
        ON (pi.ProductID = src.ProductID)
    WHEN MATCHED
        AND pi.Quantity - src.OrderQty <= 0
        THEN
            DELETE
    WHEN MATCHED
        THEN
            UPDATE
            SET pi.Quantity = pi.Quantity - src.OrderQty
    OUTPUT $ACTION,
        DELETED.ProductID
    ) AS Changes(Action, ProductID)
WHERE Action = 'DELETE';

IF @@ROWCOUNT = 0
    PRINT 'Warning: No rows were inserted';
GO

SELECT DeletedProductID,
    RemovedOnDate
FROM Production.ZeroInventory;
GO