返回受 INSERT、UPDATE、DELETE 或 MERGE 语句影响的各行中的信息,或返回基于受这些语句影响的各行的表达式。 这些结果可以返回到处理应用程序,以供在确认消息、存档以及其他类似的应用程序要求中使用。 也可以将这些结果插入表或表变量。 另外,您可以捕获嵌入的 INSERT、UPDATE、DELETE 或 MERGE 语句中 OUTPUT 子句的结果,然后将这些结果插入目标表或视图。 OUTPUT子句的基本原理1、返回由每个INSERT、UPDATE或DELETE命令所影响的记录行。OUTPUT子句可以在客户端应用程序中返回这些记录行,然后将它们插入到一个持久的或临时的表中,也可以将记录插入到一个表变量中,或直接返回到处理应用程序,也就是用于输出。 2、OUTPUT子句的用法就是直接将OUTPUT子句附到任何一个INSERT/UPDATE/DELETE语句后。 3、OUTPUT子句中可以引用INSERTED或DELETED虚拟表,这取决于是否想要在数据修改前(DELETED表)或修改后(INSERTED表)得到数据,这跟使用触发器去修改数据的操作是很相似的。 4、不能在一个INSERT语句中引用DELETED,也不能在一个DELETED语句中引用INSERTED,因为这些虚拟表在这两种情况下逻辑上是没有意义的,所以SQL Server不会去创建。 5、对于具有 OUTPUT 子句的 UPDATE、INSERT 或 DELETE 语句,即使在遇到错误需要回滚时,也会将行返回到客户端。 如果在运行语句的过程中出现任何错误,都不应使用该结果。 语法 [OUTPUT <dml_select_list> INTO {@table_variable|output_table} [(column_list)]] [OUTPUT <dml_select_list> ] { <column_name> | scalar_expression } [ [AS] column_alias_identifier ] { DELETED | INSERTED | from_table_name } . { * | column_name }
- 使用OUTPUT INTO子句的话,是把返回的结果插入到表变量(@table_variable)或表(output_table)中。
- 使用OUTPUT子句的话,就是直接把结果直接返回到处理应用程序。
- @table_variable必须先声明才能插入、 更新、 DELETE 或 MERGE 语句。
- output_table指定一个表,返回的行将被插入该表中而不是返回到调用方。output_table可能是临时表。
output_table不能︰ - 具有启用的对其定义的触发器。
- 参与 FOREIGN KEY 约束的任意一方。
- 具有 CHECK 约束或启用的规则。
- column_list
INTO 子句目标表(上面的@table_variable | output_table)上列名的可选列表。如果column_list未指定,表变量/表必须具有和输出结果集相同的列数。标识列和计算列除外,这两种列必须跳过。 - scalar_expression:可取计算结果为单个值的任何符号和运算符的组合。
- column_alias_identifier:列别名。指定受删除、插入或更新操作影响的所有列都将按照它们在表中的顺序返回。
- 在OUTPUT子句中,可以引用特殊表INSERTED和DELETED,这与在触发器中使用临时表inserted和deleted非常相似。但是OUTPUT引用的INSERTED、DELETED和触发器产生的是不一样的。
- DELETED:指定由更新或删除操作删除的值的列前缀。 以 DELETED 为前缀的列反映了 UPDATE、DELETE 或 MERGE 语句完成之前的值。
- INSERTED:列的前缀,指定由插入操作或更新操作添加的值。 以 INSERTED 为前缀的列反映了在 UPDATE、INSERT 或 MERGE 语句完成之后但在触发器执行之前的值。
- from_table_name:是一个列前缀,还可以把FROM 子句中包含的表的值OUTPUT INTO到表或表变量中。如:
DELETE Production.ProductProductPhoto OUTPUT DELETED.ProductID, FROM Production.ProductProductPhoto AS ph JOIN Production.Product as p ON ph.ProductID = p.ProductID WHERE p.ProductModelID BETWEEN 120 and 130;
- $action:仅可用于 MERGE 语句。在 MERGE 语句的 OUTPUT 子句中指定一个 nvarchar(10) 类型的列,该子句为每行返回以下三个值一:'INSERT'、'UPDATE' 或 'DELETE',返回哪个值取决于对该行执行的操作。
不支持 OUTPUT 子句1、引用本地分区视图、分布式分区视图或远程表的 DML 语句。 2、包含 EXECUTE 语句的 INSERT 语句。 3、当数据库兼容级别设为 100 时,不允许在 OUTPUT 子句中使用全文谓词。 4、不能将 OUTPUT INTO 子句插入视图或行集函数。 5、如果用户定义的函数包含一个以表为目标的 OUTPUT INTO 子句,则不能创建该函数。 将从 OUTPUT 子句返回的数据插入表在捕获嵌套的 INSERT、UPDATE、DELETE 或 MERGE 语句中 OUTPUT 子句的结果并将这些结果插入目标表时,请牢记以下信息: - 整个操作是原子的。INSERT 语句和包含 OUTPUT 子句的嵌套 DML 语句要么都执行,要么整个语句都失败。
- 以下限制适用于外层 INSERT 语句的目标:
- 目标不能为远程表、视图或公用表表达式。
- 目标不能有 FOREIGN KEY 约束,或者被 FOREIGN KEY 约束所引用。
- 不能对目标定义触发器。
- 目标不能参与合并复制或事务复制的可更新订阅。
- 在包含 <dml_table_source> 子句的 INSERT 语句中不支持 OUTPUT INTO 子句,只能使用OUTPUT语句。如:
INSERT INTO Production.ScrapReason (Name, ModifiedDate) OUTPUT INSERTED.ScrapReasonID, INSERTED.Name,
- @@ROWCOUNT 返回仅由外层 INSERT 语句插入的行。
- 在 <dml_table_source> 子句中,SELECT 和 WHERE 子句不能包括子查询、聚合函数、排名函数、全文谓词、执行数据访问的用户定义函数或是 TEXTPTR 函数
使用包含 OUTPUT 的 DML 触发器从 OUTPUT 中返回的列反映** INSERT、UPDATE 或 DELETE 语句完成之后但在触发器执行之前的数据。 对于 INSTEAD OF 触发器,即使没有因为触发器的操作而发生修改,也会如同实际执行 INSERT、UPDATE 或 DELETE 那样生成返回的结果。如果在触发器的主体内使用包含 OUTPUT 子句的语句,则必须使用表别名来引用触发器 inserted 和 deleted 表,以免使用与OUTPUT 关联的 INSERTED 和 DELETED 表复制列引用**。 如果指定了 OUTPUT 子句但未同时指定 INTO 关键字,则对于给定的 DML 操作,DML 操作的目标不能启用对其定义的任何触发器。例如,如果在 UPDATE 语句中定义了 OUTPUT 子句,则目标表不能具有任何启用的 UPDATE 触发器。 如果设置了 sp_configure 选项 disallow results from triggers,则从触发器内调用语句时,不带 INTO 子句的 OUTPUT 子句将导致该语句失败。 队列SQL Server 并不保证由使用 OUTPUT 子句的 DML 语句处理和返回行的顺序。应用程序负责包括可保证所需语义的适当 WHERE 子句,或者理解当针对 DML 操作可能限定多行时,没有保证的顺序。以下示例使用子查询,并假定 DatabaseLogID 列具有唯一性特征才能实现所需的排序语义。 INSERT INTO dbo.table1 VALUES DECLARE @MyTableVar TABLE PRINT 'table1, before delete' SELECT * FROM dbo.table1; OUTPUT DELETED.* INTO @MyTableVar PRINT 'table1, after delete' SELECT * FROM dbo.table1; PRINT '@MyTableVar, after delete' SELECT * FROM @MyTableVar; ------------- ------------------------------ ------------- ------------------------------ --@MyTableVar, after delete ------------- ------------------------------
【示例】 A、使用 OUTPUT INTO 返回表达式 USE AdventureWorks2008R2; DECLARE @MyTableVar table( VacationHoursDifference int, UPDATE TOP (10) HumanResources.Employee SET VacationHours = VacationHours * 1.25, OUTPUT inserted.BusinessEntityID, inserted.VacationHours - deleted.VacationHours,
B、使用包含 from_table_name 的 OUTPUT INTO USE AdventureWorks2008R2; DECLARE @MyTableVar table ( ProductName nvarchar(50)NOT NULL, ProductModelID int NOT NULL, DELETE Production.ProductProductPhoto OUTPUT DELETED.ProductID, FROM Production.ProductProductPhoto AS ph JOIN Production.Product as p ON ph.ProductID = p.ProductID WHERE p.ProductModelID BETWEEN 120 and 130;
C、将 OUTPUT INTO 用于大型对象数据类型 以下示例使用 .WRITE 子句更新 Production.Document 表内 DocumentSummary 这一 nvarchar(max) 列中的部分值。通过指定替换单词、现有数据中要替换的单词的开始位置(偏移量)以及要替换的字符数(长度),将单词 components 替换为单词 features。此示例使用 OUTPUT 子句将 DocumentSummary 列的前像和后像返回到 @MyTableVartable 变量。 USE AdventureWorks2008R2; DECLARE @MyTableVar table ( SummaryBefore nvarchar(max), SummaryAfter nvarchar(max)); UPDATE Production.Document SET DocumentSummary .WRITE (N'features',28,10) OUTPUT deleted.DocumentSummary, WHERE Title = N'Front Reflector Bracket Installation';
D、将 OUTPUT INTO 用于标识列和计算列 下例创建了 EmployeeSales 表,然后使用 INSERT 语句向该表中插入若干行,其中 SELECT 语句用来从源表中检索数据。EmployeeSales 表包含标识列 (EmployeeID) 和计算列 (ProjectedSales)。由于这些值是在插入操作期间由 SQL Server 数据库引擎生成的,因此,不能在 @MyTableVar 中定义上述两列。 USE AdventureWorks2008R2 ; IF OBJECT_ID ('dbo.EmployeeSales', 'U') IS NOT NULL DROP TABLE dbo.EmployeeSales; 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 DECLARE @MyTableVar table( LastName nvarchar(20) NOT NULL, FirstName nvarchar(20) NOT NULL, CurrentSales money NOT NULL INSERT INTO dbo.EmployeeSales (LastName, FirstName, CurrentSales) OUTPUT INSERTED.LastName, 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 LastName, FirstName, CurrentSales
E、在单个语句中使用 OUTPUT 和 OUTPUT INTO 以下示例将按照在 DELETE 语句的 FROM 子句中所定义的搜索条件删除ProductProductPhoto 表中的行。OUTPUT INTO 子句将被删除表中的列(deleted.ProductID、deleted.ProductPhotoID)及Product 表中的列返回给@MyTableVartable 变量。 OUTPUT 子句将 ProductProductPhoto 表中的 deleted.ProductID、deleted.ProductPhotoID 列以及行的删除日期和时间返回到执行调用的应用程序。 USE AdventureWorks2008R2; DECLARE @MyTableVar table ( ProductName nvarchar(50)NOT NULL, ProductModelID int NOT NULL, DELETE Production.ProductProductPhoto -- 用于将被删除的列返回给@MyTableVartable变量 OUTPUT DELETED.ProductID, OUTPUT DELETED.ProductID, DELETED.ProductPhotoID, GETDATE() AS DeletedDate FROM Production.ProductProductPhoto AS ph JOIN Production.Product as p ON ph.ProductID = p.ProductID WHERE p.ProductID BETWEEN 800 and 810;
F、插入从 OUTPUT 子句返回的数据 下面的示例捕获从 MERGE 语句的 OUTPUT 子句返回的数据,并将这些数据插入另一个表。 CREATE TABLE table1 (id INT, employee VARCHAR(32)); CREATE TABLE table2(id INT,person VARCHAR(32)); SELECT a.id,a.person FROM ( OUTPUT INSERTED.id,INSERTED.person
G、在 INSTEAD OF 触发器中使用 OUTPUT 下例在触发器中使用 OUTPUT 子句来返回触发器操作的结果。首先,创建一个 ScrapReason 表的视图,然后对该视图定义 INSTEAD OF INSERT 触发器,从而使用户只修改基表的 Name 列。OUTPUT 子句返回实际插入 ScrapReason 表中的值。 CREATE VIEW dbo.vw_ScrapReason AS (SELECT ScrapReasonID, Name, ModifiedDate FROM Production.ScrapReason); CREATE TRIGGER dbo.io_ScrapReason -- inserted表是触发器执行的时候临时产生的 -- INSERTED表是DML操作(这里为INSERT)完成之后产生的 INSERT INTO Production.ScrapReason (Name, ModifiedDate) OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, SELECT Name, getdate() FROM inserted; INSERT vw_ScrapReason (ScrapReasonID, Name, ModifiedDate) VALUES (99, N'My scrap reason','20030404');
|