在sql server中使用OUTPUT子句有什么用

时间:2014-01-09 11:02:14

标签: sql-server tsql

OUTPUT条款的目的是什么?我已经查看了OUTPUT DELETE FROM dbo.table1 OUTPUT DELETED.* INTO @MyTableVar WHERE id = 4 OR id = 2; 子句,其中包括以下示例:

deleted

从上面的查询中,似乎已删除的记录保存在一个名为deleted的魔术表中,并且查询会将这些记录从魔术OUTPUT表加载到名为MyTableVar的表中。

我仍然不明白USE AdventureWorks2012; 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 子句用法的目的。

另一个SQL示例:

create proc test
as
CREATE TABLE dbo.table1
(
    id INT,
    employee VARCHAR(32)
)
go

INSERT INTO dbo.table1 VALUES 
      (1, 'Fred')
     ,(2, 'Tom')
     ,(3, 'Sally')
     ,(4, 'Alice')
delete from table1
select * from deleted

这实际上是做什么的?任何人都可以通过一个简单的例子解释这个子句的用途吗?

更新非功能性示例:

deleted

当我运行它时,这给了我一个错误,因为它看不到{{1}}表。

3 个答案:

答案 0 :(得分:7)

此子句的一般目的是捕获对数据所做的更改,而无需额外的查询,这会引入锁定和阻塞问题。例如:

DELETE FROM X WHERE Name = 'Foo'

您想知道哪些ID已被删除。你可以像这样天真地做到这一点:

SELECT ID FROM X WHERE Name = 'Foo'
DELETE FROM X WHERE Name = 'Foo'

但是这些选定的ID是不可靠的,除非您在隔离级别为SERIALIZABLE的事务中运行,而通常情况并非如此。其他人可以添加,删除或更改两个语句之间的“Foo” - 记录。因此,您可以使用OUTPUT子句并准确可靠地获取已删除的ID,而不会出现任何性能或可靠性问题。

另一种常用方法是获取插入的默认值的值,尤其是在使用标识列时。对于单个插入,您可以执行此操作:

CREATE TABLE X
 (
 ID INT IDENTITY,
 Name VARCHAR(10)
 );

INSERT X (Name) VALUES ('Foo')

SELECT SCOPE_IDENTITY()

但是SCOPE_IDENTITY()只能为您提供最后插入的ID。如果你做了多个插入,比如

INSERT X (Name) VALUES ('Foo'), ('Bar')

INSERT X (Name) SELECT OtherName FROM Y

你想知道插入的ID,你运气不好。您可以尝试使用另一个SELECT找到它们,但是您需要另一个唯一列来甚至制定查询,然后您遇到与上面的DELETE示例相同的问题。因此,OUTPUT子句可以让您整齐地识别哪些名称具有哪些ID。

例如,在使用外键创建相关记录时,您将需要这些ID。认为“Order”和“OrderDetails”由OrderID列与IDENTITY子句链接。同样,使用单个INSERT,您可以使用SCOPE_IDENTITY()@@IDENTITY,但在一次插入多个订单时,您需要OUTPUT

答案 1 :(得分:1)

当您对特定表执行插入/更新/删除操作并想知道哪些行受影响或想要将它们记录为审计跟踪时,或者您希望在后续sql语句中使用受影响行的多个值时,可以使用{ {1}}条款。

对于Insert语句,它将有OUTPUT表。

对于Delete语句,它将具有INSERTED表。如果Update DELETED表将在执行更新操作之前包含行(具有旧值)。

对于Update语句,它将包含DELETEDDELETED个表。 INSERTED表将在执行更新操作之前包含行(具有旧值)。 执行更新操作后,DELETED表将包含行(带有新值)。

INSERTED

现在,您的查询会在USE AdventureWorks2012; 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; 以及表变量Production.ScrapReason中插入行。稍后,它会从@MyTableVarProduction.ScrapReason中选择插入的行。因此,您可以比较结果集,并且它必须具有相同的行(考虑@MyTableVar是空表。)

我希望它有意义!

修改

插入/删除表格将在插入/更新/删除语句中提供,之后不会。您可能希望将这些魔术表值存储在db table或temp table中。

答案 2 :(得分:0)

如果没有OUTPUT子句,您如何知道删除了哪些行?您的示例看起来很简单,因为您已经知道了Id值,但是如果您这样做会怎样:

DELETE FROM T WHERE SomeColumn LIKE 'SomePattern%'

你想找出被删除的内容。这就是OUTPUT条款的目的。