OUTPUT 子句 (Transact-SQL)
适用于: SQL Server Azure SQL 数据库 Azure SQL 托管实例
根据受 、INSERT
UPDATE
、DELETE
或MERGE
语句影响的每一行返回信息或表达式。 这些结果可以返回到处理应用程序,以供在确认消息、存档以及其他类似的应用程序要求中使用。 也可以将这些结果插入表或表变量。 此外,还可以捕获嵌套INSERT
、UPDATE
或MERGE
DELETE
语句中子OUTPUT
句的结果,并将这些结果插入目标表或视图中。
注意
UPDATE
包含OUTPUT
子句的语句INSERT
将返回行给客户端,DELETE
即使该语句遇到错误并回滚。 如果在运行语句的过程中出现任何错误,都不应使用该结果。
用于以下语句:
语法
<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必须在 DELETE
@table_variable 或MERGE
语句之前INSERT
声明。
如果未指定 column_list,则 table 变量必须与 OUTPUT
结果集具有相同的列数。 标识列和计算列除外,这两种列必须跳过。 如果指定了 column_list,则任何省略的列都必须允许 NULL 值,或者都分配有默认值。
有关表变量的详细信息,请参阅表。
output_table
指定一个表,返回的行将插入该表中而不是返回到调用方。 output_table可能是临时表。
如果未指定 column_list,则 table 必须与 OUTPUT
结果集具有相同的列数。 标识列和计算列除外,这两种列必须跳过。 如果指定了 column_list,则任何省略的列都必须允许 NULL 值,或者都分配有默认值。
output_table 无法:
- 具有启用的对其定义的触发器。
- 参与约束的任一
FOREIGN KEY
端。 - 具有
CHECK
约束或启用的规则。
column_list
子句的目标表中的列名称的 INTO
可选列表。 这类似于 INSERT 语句中允许的列列表。
scalar_expression
计算结果为单个值的任何符号和运算符的组合。 scalar_expression 中不允许使用聚合函数。
对要修改的表中的列的任何引用都必须使用 INSERTED
或 DELETED
前缀进行限定。
column_alias_identifier
用于引用列名的替换名称。
DELETED
一个列前缀,指定更新或删除操作删除的值,以及不随当前操作更改的任何现有值。 带有前缀的DELETED
列在完成或语句之前UPDATE
DELETE
MERGE
反映值。
DELETED
不能与语句中的INSERT
子句一起使用OUTPUT
。
INSERTED
一个列前缀,指定插入或更新操作添加的值,以及不随当前操作更改的任何现有值。 带有前缀INSERTED
的UPDATE
INSERT
列在完成或语句之后反映值,MERGE
但在执行触发器之前。
INSERTED
不能与语句中的DELETE
子句一起使用OUTPUT
。
from_table_name
一个列前缀,指定包含在子句中的FROM
DELETE
UPDATE
表,或MERGE
用于指定要更新或删除的行的语句。
如果在子句中还指定了要修改的 FROM
表,则对该表中的列的任何引用都必须使用 INSERTED
或 DELETED
前缀进行限定。
*
星号 (*
) 指定返回受删除、插入或更新操作影响的所有列,其顺序在表中存在。
例如, OUTPUT DELETED.*
在以下 DELETE
语句中返回从 ShoppingCartItem
表中删除的所有列:
DELETE Sales.ShoppingCartItem
OUTPUT DELETED.*;
column_name
显式列引用。 对要修改的表的任何引用都必须由INSERTED
相应前缀DELETED
正确限定,例如: INSERTED.<column_name>
$action
仅适用于 MERGE
语句。 在语句中OUTPUT
指定类型为 nvarchar(10)的列,该列返回每行的三个MERGE
值之一:INSERT
,UPDATE
或DELETE
根据对该行执行的操作。
注解
子OUTPUT <dml_select_list>
句和OUTPUT <dml_select_list> INTO { @table_variable | output_table }
子句可以在单个INSERT
、UPDATE
或DELETE
MERGE
语句中定义。
注意
除非另行指定,否则,引用 OUTPUT
子句将同时引用 OUTPUT
子句和 OUTPUT INTO
子句。
子OUTPUT
句在或操作后INSERT
UPDATE
检索标识列或计算列的值可能很有用。
当 <dml_select_list>
中包含计算列时,输出表或表变量中的相应列并不是计算列。 新列中的值是在执行该语句时计算出的值。
无法保证更改应用于表的顺序以及行插入到输出表或表变量的顺序。
如果参数或变量作为语句的一 UPDATE
部分进行修改,则 OUTPUT
子句始终返回参数或变量的值,就像执行语句之前那样返回参数或变量的值,而不是修改的值。
可以在OUTPUT
UPDATE
使用WHERE CURRENT OF
语法的游标上使用或DELETE
语句。
以下语句中不支持 OUTPUT
子句:
引用本地分区视图、分布式分区视图或远程表的 DML 语句。
INSERT
包含语句的EXECUTE
语句。当数据库兼容级别设置为 100 时,不允许在
OUTPUT
子句中使用全文谓词。不能将
OUTPUT INTO
子句插入视图或行集函数。如果用户定义函数包含具有
OUTPUT INTO
表作为其目标的子句,则无法创建该函数。
若要防止出现不确定的行为,OUTPUT
子句不能包含以下引用:
执行用户或系统数据访问的子查询或用户定义函数,或者被认定会执行此类访问的子查询或用户定义函数。 如果用户定义函数未绑定到架构,则认定它会执行数据访问。
视图或内嵌表值函数中的一个列(如果该列由以下方法之一定义):
子查询。
执行用户数据访问或系统数据访问或者被认为执行此种访问的用户定义函数。
定义中包含执行用户数据访问或系统数据访问的用户定义函数的计算列。
如果 SQL Server 在
OUTPUT
子句中检测到了此类列,将引发错误 4186。
将从 OUTPUT 子句返回的数据插入表
在嵌套INSERT
、DELETE
UPDATE
或MERGE
语句中捕获子句的结果OUTPUT
并将这些结果插入目标表中时,请记住以下信息:
整个操作是原子的。
INSERT
语句和包含OUTPUT
子句执行的嵌套 DML 语句或整个语句都失败。以下限制适用于外部
INSERT
语句的目标:目标不能为远程表、视图或公用表表达式。
目标不能有
FOREIGN KEY
约束,也不能由FOREIGN KEY
约束引用。不能对目标定义触发器。
目标不能参与合并复制或事务复制的可更新订阅。
对于嵌套的 DML 语句有以下限制:
目标不能为远程表或分区视图。
源本身不能包含
<dml_table_source>
子句。
包含
<dml_table_source>
子句的语句不支持INSERT
该OUTPUT INTO
子句。@@ROWCOUNT
返回仅由外部INSERT
语句插入的行。@@IDENTITY
、SCOPE_IDENTITY
和IDENT_CURRENT
返回标识值,仅由嵌套 DML 语句生成,而不是由外部INSERT
语句生成的值。查询通知将语句视为单个实体,创建的任何消息的类型都是嵌套 DML 的类型,即使重大更改来自外部
INSERT
语句本身也是如此。在该子句中
<dml_table_source>
,SELECT
子WHERE
句不能包括子查询、聚合函数、排名函数、全文谓词、执行数据访问的用户定义函数或TEXTPTR()
函数。
并行度
向 OUTPUT
客户端或表变量返回结果的子句始终使用串行计划。
在数据库设置为兼容级别 130 或更高版本的上下文中,如果 INSERT...SELECT
操作使用 WITH (TABLOCK)
语句的提示 SELECT
,并且还用于 OUTPUT...INTO
插入临时表或用户表中,则目标表 INSERT...SELECT
符合并行度的条件,具体取决于子树成本。 子句中 OUTPUT INTO
引用的目标表不符合并行度的条件。
触发器
从OUTPUT
返回的列反映数据,因为它在完成、UPDATE
或DELETE
语句之后INSERT
,但在执行触发器之前。
对于INSTEAD OF
触发器,返回的结果会生成为INSERT
UPDATE
DELETE
触发器操作的结果(即使没有发生任何修改),也是如此。 如果在触发器正文中使用包含OUTPUT
子句的语句,则必须使用表别名来引用插入和删除的触发器,以避免与INSERTED
关联的OUTPUT
表DELETED
复制列引用。
OUTPUT
如果在未指定关键字的情况下指定INTO
子句,则 DML 操作的目标不能为其定义给定 DML 操作的任何已启用触发器。 例如,如果在 OUTPUT
语句中 UPDATE
定义了子句,则目标表不能有任何已启用 UPDATE
的触发器。
sp_configure
如果设置了选项禁止触发器的结果,OUTPUT
则不INTO
带子句的子句会导致从触发器中调用语句时失败。
数据类型
OUTPUT
子句支持大型对象数据类型:nvarchar(max)、varchar(max)、varbinary(max)、text、ntext、image 和 xml。 使用 .WRITE
语句中的 UPDATE
子句修改 nvarchar(max)、 varchar(max)或 varbinary(max) 列时,如果引用值的图像前后,将返回完整的值。 在 OUTPUT
子句中,TEXTPTR()
函数不能作为 text、ntext 或 image 列的表达式的一部分出现。
队列
可以在将表用作队列或将表用于保持中间结果集的应用程序中使用 OUTPUT
。 换句话说,应用程序不断地在表中添加或删除行。 以下示例使用 OUTPUT
语句中的 DELETE
子句将已删除的行返回到调用应用程序。
USE AdventureWorks2022;
GO
DELETE TOP(1) dbo.DatabaseLog WITH (READPAST)
OUTPUT DELETED.*
WHERE DatabaseLogID = 7;
GO
此示例从用作队列的表中删除一行,并使用单个操作将已删除的值返回到处理应用程序。 还可以实现其他语义,例如使用表实现堆栈。 但是,SQL Server 并不保证由使用 OUTPUT
子句的 DML 语句处理和返回行的顺序。 应用程序可以包含可保证所需语义的相应 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
如果方案允许多个应用程序从一个表执行破坏性读取,请使用表提示UPDATE
和DELETE
语句。 这可防止在其他应用程序已经读取表中第一个限定记录的情况下出现锁定问题。
权限
SELECT
对于通过 <dml_select_list>
检索或使用的任何 <scalar_expression>
列,都需要权限。
INSERT
对于在 .. 中指定的 <output_table>
任何表,都需要权限。
示例
本文中的 Transact-SQL 代码示例使用 AdventureWorks2022
或 AdventureWorksDW2022
示例数据库,可从 Microsoft SQL Server 示例和社区项目主页下载它。
A. 将 OUTPUT INTO 用于 INSERT 语句
下面的示例将行插入到 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. 将 OUTPUT 与 DELETE 语句一起使用
以下示例将删除 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. 将 OUTPUT INTO 与 UPDATE 语句一起使用
下面的示例将 VacationHours
表中 Employee
列的前 10 行更新 25%。 OUTPUT
子句将返回 VacationHours
值,该值在将 UPDATE
列中的 DELETED.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
以下示例使用指定的 ProductID
和 ScrapReasonID
,针对 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.ProductID
、DELETED.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.Document
的部分值DocumentSummary
。 通过指定替换单词、现有数据中要替换的单词的开始位置(偏移量)以及要替换的字符数(长度),将单词 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'
) 生成的结果集。 和ScrapReasonIDActual
ModifiedDate
列反映触发器操作生成的值,而不是语句中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.ProductID
、DELETED.ProductPhotoID
)及 Product
表中的列返回给 @MyTableVar
表变量。 在 Product
子句中使用 FROM
表来指定要删除的行。 子OUTPUT
句将DELETED.ProductID
行从ProductProductPhoto
表中删除的日期和时间返回调用应用程序。 DELETED.ProductPhotoID
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