OUTPUT 子句

返回受 INSERT、UPDATE、DELETE 或 MERGE 語句影響的各行中的信息,或返回基于受這些語句影響的各行的表達(dá)式。 這些結(jié)果可以返回到處理應(yīng)用程序,以供在確認(rèn)消息、存檔以及其他類似的應(yīng)用程序要求中使用。 也可以將這些結(jié)果插入表或表變量。 另外,您可以捕獲嵌入的 INSERT、UPDATE、DELETE 或 MERGE 語句中 OUTPUT 子句的結(jié)果,然后將這些結(jié)果插入目標(biāo)表或視圖。

OUTPUT子句的基本原理

1、返回由每個(gè)INSERT、UPDATE或DELETE命令所影響的記錄行。OUTPUT子句可以在客戶端應(yīng)用程序中返回這些記錄行,然后將它們插入到一個(gè)持久的或臨時(shí)的表中,也可以將記錄插入到一個(gè)表變量中,或直接返回到處理應(yīng)用程序,也就是用于輸出。
2、OUTPUT子句的用法就是直接將OUTPUT子句附到任何一個(gè)INSERT/UPDATE/DELETE語句后。
3、OUTPUT子句中可以引用INSERTED或DELETED虛擬表,這取決于是否想要在數(shù)據(jù)修改前(DELETED表)或修改后(INSERTED表)得到數(shù)據(jù),這跟使用觸發(fā)器去修改數(shù)據(jù)的操作是很相似的。
4、不能在一個(gè)INSERT語句中引用DELETED,也不能在一個(gè)DELETED語句中引用INSERTED,因?yàn)檫@些虛擬表在這兩種情況下邏輯上是沒有意義的,所以SQL Server不會(huì)去創(chuàng)建。
5、對(duì)于具有 OUTPUT 子句的 UPDATE、INSERT 或 DELETE 語句,即使在遇到錯(cuò)誤需要回滾時(shí),也會(huì)將行返回到客戶端。 如果在運(yùn)行語句的過程中出現(xiàn)任何錯(cuò)誤,都不應(yīng)使用該結(jié)果。

語法

<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
  • 使用OUTPUT INTO子句的話,是把返回的結(jié)果插入到表變量(@table_variable)或表(output_table)中。
  • 使用OUTPUT子句的話,就是直接把結(jié)果直接返回到處理應(yīng)用程序。
  • @table_variable必須先聲明才能插入、 更新、 DELETE 或 MERGE 語句。
  • output_table指定一個(gè)表,返回的行將被插入該表中而不是返回到調(diào)用方。output_table可能是臨時(shí)表。
    ??output_table不能︰
  • 具有啟用的對(duì)其定義的觸發(fā)器。
  • 參與 FOREIGN KEY 約束的任意一方。
  • 具有 CHECK 約束或啟用的規(guī)則。
  • column_list
    ??INTO 子句目標(biāo)表(上面的@table_variable | output_table)上列名的可選列表。如果column_list未指定,表變量/表必須具有和輸出結(jié)果集相同的列數(shù)。標(biāo)識(shí)列和計(jì)算列除外,這兩種列必須跳過。
  • scalar_expression:可取計(jì)算結(jié)果為單個(gè)值的任何符號(hào)和運(yùn)算符的組合。
  • column_alias_identifier:列別名。指定受刪除、插入或更新操作影響的所有列都將按照它們?cè)诒碇械捻樞蚍祷亍?/li>
  • 在OUTPUT子句中,可以引用特殊表INSERTED和DELETED,這與在觸發(fā)器中使用臨時(shí)表inserted和deleted非常相似。但是OUTPUT引用的INSERTED、DELETED和觸發(fā)器產(chǎn)生的是不一樣的。
  • DELETED:指定由更新或刪除操作刪除的值的列前綴。 以 DELETED 為前綴的列反映了 UPDATE、DELETE 或 MERGE 語句完成之前的值。
  • INSERTED:列的前綴,指定由插入操作或更新操作添加的值。 以 INSERTED 為前綴的列反映了在 UPDATE、INSERT 或 MERGE 語句完成之后但在觸發(fā)器執(zhí)行之前的值。
  • from_table_name:是一個(gè)列前綴,還可以把FROM 子句中包含的表的值OUTPUT INTO到表或表變量中。如:
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;  
  • $action:僅可用于 MERGE 語句。在 MERGE 語句的 OUTPUT 子句中指定一個(gè) nvarchar(10) 類型的列,該子句為每行返回以下三個(gè)值一:'INSERT'、'UPDATE' 或 'DELETE',返回哪個(gè)值取決于對(duì)該行執(zhí)行的操作。

不支持 OUTPUT 子句

1、引用本地分區(qū)視圖、分布式分區(qū)視圖或遠(yuǎn)程表的 DML 語句。
2、包含 EXECUTE 語句的 INSERT 語句。
3、當(dāng)數(shù)據(jù)庫兼容級(jí)別設(shè)為 100 時(shí),不允許在 OUTPUT 子句中使用全文謂詞。
4、不能將 OUTPUT INTO 子句插入視圖或行集函數(shù)。
5、如果用戶定義的函數(shù)包含一個(gè)以表為目標(biāo)的 OUTPUT INTO 子句,則不能創(chuàng)建該函數(shù)。

將從 OUTPUT 子句返回的數(shù)據(jù)插入表

在捕獲嵌套的 INSERT、UPDATE、DELETE 或 MERGE 語句中 OUTPUT 子句的結(jié)果并將這些結(jié)果插入目標(biāo)表時(shí),請(qǐng)牢記以下信息:

  • 整個(gè)操作是原子的。INSERT 語句和包含 OUTPUT 子句的嵌套 DML 語句要么都執(zhí)行,要么整個(gè)語句都失敗。
  • 以下限制適用于外層 INSERT 語句的目標(biāo):
  • 目標(biāo)不能為遠(yuǎn)程表、視圖或公用表表達(dá)式。
  • 目標(biāo)不能有 FOREIGN KEY 約束,或者被 FOREIGN KEY 約束所引用。
  • 不能對(duì)目標(biāo)定義觸發(fā)器。
  • 目標(biāo)不能參與合并復(fù)制或事務(wù)復(fù)制的可更新訂閱。
  • 在包含 <dml_table_source> 子句的 INSERT 語句中不支持 OUTPUT INTO 子句,只能使用OUTPUT語句。如:
 INSERT INTO Production.ScrapReason (Name, ModifiedDate)
        OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, 
               INSERTED.ModifiedDate
    SELECT Name, getdate()
    FROM INSERTED;
  • @@ROWCOUNT 返回僅由外層 INSERT 語句插入的行。
  • 在 <dml_table_source> 子句中,SELECT 和 WHERE 子句不能包括子查詢、聚合函數(shù)、排名函數(shù)、全文謂詞、執(zhí)行數(shù)據(jù)訪問的用戶定義函數(shù)或是 TEXTPTR 函數(shù)

使用包含 OUTPUT 的 DML 觸發(fā)器

從 OUTPUT 中返回的列反映** INSERT、UPDATE 或 DELETE 語句完成之后但在觸發(fā)器執(zhí)行之前的數(shù)據(jù)。
??對(duì)于
INSTEAD OF 觸發(fā)器,即使沒有因?yàn)橛|發(fā)器的操作而發(fā)生修改,也會(huì)如同實(shí)際執(zhí)行 INSERT、UPDATE 或 DELETE 那樣生成返回的結(jié)果。如果在觸發(fā)器的主體內(nèi)使用包含 OUTPUT 子句的語句,則必須使用表別名來引用觸發(fā)器 inserted 和 deleted 表,以免使用與OUTPUT 關(guān)聯(lián)的 INSERTED 和 DELETED 表復(fù)制列引用**。
??如果指定了 OUTPUT 子句但未同時(shí)指定 INTO 關(guān)鍵字,則對(duì)于給定的 DML 操作,DML 操作的目標(biāo)不能啟用對(duì)其定義的任何觸發(fā)器。例如,如果在 UPDATE 語句中定義了 OUTPUT 子句,則目標(biāo)表不能具有任何啟用的 UPDATE 觸發(fā)器。
??如果設(shè)置了 sp_configure 選項(xiàng) disallow results from triggers,則從觸發(fā)器內(nèi)調(diào)用語句時(shí),不帶 INTO 子句的 OUTPUT 子句將導(dǎo)致該語句失敗。

隊(duì)列

SQL Server 并不保證由使用 OUTPUT 子句的 DML 語句處理和返回行的順序。應(yīng)用程序負(fù)責(zé)包括可保證所需語義的適當(dāng) WHERE 子句,或者理解當(dāng)針對(duì) DML 操作可能限定多行時(shí),沒有保證的順序。以下示例使用子查詢,并假定 DatabaseLogID 列具有唯一性特征才能實(shí)現(xiàn)所需的排序語義。

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;

--Results
--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

【示例】
A、使用 OUTPUT INTO 返回表達(dá)式

USE AdventureWorks2008R2;
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,
       -- scalar_expression
       inserted.VacationHours - deleted.VacationHours,
       inserted.ModifiedDate
INTO @MyTableVar;

B、使用包含 from_table_name 的 OUTPUT INTO

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

C、將 OUTPUT INTO 用于大型對(duì)象數(shù)據(jù)類型
??以下示例使用 .WRITE 子句更新 Production.Document 表內(nèi) DocumentSummary 這一 nvarchar(max) 列中的部分值。通過指定替換單詞、現(xiàn)有數(shù)據(jù)中要替換的單詞的開始位置(偏移量)以及要替換的字符數(shù)(長度),將單詞 components 替換為單詞 features。此示例使用 OUTPUT 子句將 DocumentSummary 列的前像和后像返回到 @MyTableVartable 變量。

USE AdventureWorks2008R2;
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';

D、將 OUTPUT INTO 用于標(biāo)識(shí)列和計(jì)算列
??下例創(chuàng)建了 EmployeeSales 表,然后使用 INSERT 語句向該表中插入若干行,其中 SELECT 語句用來從源表中檢索數(shù)據(jù)。EmployeeSales表包含標(biāo)識(shí)列 (EmployeeID) 和計(jì)算列 (ProjectedSales)。由于這些值是在插入操作期間由 SQL Server 數(shù)據(jù)庫引擎生成的,因此,不能在 @MyTableVar中定義上述兩列。

USE AdventureWorks2008R2 ;
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(
  LastName     nvarchar(20) NOT NULL,
  FirstName    nvarchar(20) NOT NULL,
  CurrentSales money NOT NULL
);

INSERT INTO dbo.EmployeeSales (LastName, FirstName, CurrentSales)
  OUTPUT INSERTED.LastName, 
         INSERTED.FirstName, 
         INSERTED.CurrentSales
  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 LastName, FirstName, CurrentSales
FROM @MyTableVar;
GO

E、在單個(gè)語句中使用 OUTPUT 和 OUTPUT INTO
??以下示例將按照在 DELETE 語句的 FROM 子句中所定義的搜索條件刪除ProductProductPhoto表中的行。OUTPUT INTO 子句將被刪除表中的列(deleted.ProductID、deleted.ProductPhotoID)及Product表中的列返回給@MyTableVartable變量。
??OUTPUT 子句將 ProductProductPhoto 表中的 deleted.ProductID、deleted.ProductPhotoID 列以及行的刪除日期和時(shí)間返回到執(zhí)行調(diào)用的應(yīng)用程序。

USE AdventureWorks2008R2;
GO
DECLARE @MyTableVar table (
    ProductID int NOT NULL, 
    ProductName nvarchar(50)NOT NULL,
    ProductModelID int NOT NULL, 
    PhotoID int NOT NULL);

DELETE Production.ProductProductPhoto
-- 用于將被刪除的列返回給@MyTableVartable變量
OUTPUT DELETED.ProductID,
       p.Name,
       p.ProductModelID,
       DELETED.ProductPhotoID
    INTO @MyTableVar
-- 用于把指定信息信息返回到執(zhí)行調(diào)用的應(yīng)用程序
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;
GO

F、插入從 OUTPUT 子句返回的數(shù)據(jù)
??下面的示例捕獲從 MERGE 語句的 OUTPUT 子句返回的數(shù)據(jù),并將這些數(shù)據(jù)插入另一個(gè)表。

CREATE TABLE table1  (id INT,  employee VARCHAR(32));  
CREATE TABLE table2(id INT,person VARCHAR(32));  
GO
INSERT INTO table1 
SELECT a.id,a.person FROM (
   INSERT table2 
     OUTPUT INSERTED.id,INSERTED.person
   VALUES(1,'Ada')
) AS a
GO

G、在 INSTEAD OF 觸發(fā)器中使用 OUTPUT
??下例在觸發(fā)器中使用 OUTPUT 子句來返回觸發(fā)器操作的結(jié)果。首先,創(chuàng)建一個(gè) ScrapReason 表的視圖,然后對(duì)該視圖定義 INSTEAD OF INSERT 觸發(fā)器,從而使用戶只修改基表的 Name 列。OUTPUT 子句返回實(shí)際插入 ScrapReason 表中的值。

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
   -- inserted表是觸發(fā)器執(zhí)行的時(shí)候臨時(shí)產(chǎn)生的
   -- INSERTED表是DML操作(這里為INSERT)完成之后產(chǎn)生的
    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
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 使用 INSERT 和 VALUES 插入行 INSERT 語句可向表中添加一個(gè)或多個(gè)新行。在簡化處理中,INSE...
    不知名的蛋撻閱讀 8,105評(píng)論 0 2
  • 1.1 基本結(jié)構(gòu) PL/SQL程序由三個(gè)塊組成,即聲明部分、執(zhí)行部分、異常處理部分。 1.2 命名規(guī)則 1.3 記...
    慢清塵閱讀 3,892評(píng)論 3 14
  • 語 句 功 能 數(shù)據(jù)操作 SELECT——從數(shù)據(jù)庫表中檢索數(shù)據(jù)行和列INSERT——向數(shù)據(jù)庫表添加新數(shù)據(jù)行DELE...
    戰(zhàn)敭閱讀 5,116評(píng)論 0 53
  • 1. 簡介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存儲(chǔ)過程以及高級(jí)映射的優(yōu)秀的...
    笨鳥慢飛閱讀 5,605評(píng)論 0 4
  • 她很獨(dú)寂,總會(huì)漫無目的的尋覓。 她遠(yuǎn)望天際,聽見了宇宙外的另一種聲音。 她想去遠(yuǎn)方,去流浪,去想像; 卻害怕路上布...
    阿米的貓閱讀 117評(píng)論 0 0