两个语句在功能上是一样的,但两个语句在执行机制是什么区别,性能会有差别吗

解决方案 »

  1.   

    语法
     
    <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 必须在 INSERT、UPDATE、DELETE 或 MERGE 语句前声明。如果未指定 column_list,则 table 变量必须与 OUTPUT 结果集具有相同的列数。标识列和计算列除外,这两种列必须跳过。如果指定了 column_list,则任何省略的列都必须允许 Null 值,或者都分配有默认值。有关 table 变量的详细信息,请参阅 表 (Transact-SQL)。output_table 
    指定一个表,返回的行将被插入该表中而不是返回到调用方。output_table 可以为临时表。如果未指定 column_list,则表必须与 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 语句完成之前的值。不能在 INSERT 语句中同时使用 DELETED 与 OUTPUT 子句。INSERTED
    列的前缀,指定由插入操作或更新操作添加的值。以 INSERTED 为前缀的列反映了在 UPDATE、INSERT 或 MERGE 语句完成之后但在触发器执行之前的值。INSERTED 语句不能与 DELETE 语句的 OUTPUT 子句同时使用。from_table_name 
    是一个列前缀,指定 DELETE、UPDATE 或 MERGE 语句(用于指定要更新或删除的行)的 FROM 子句中包含的表。如果还在 FROM 子句中指定了要修改的表,则对该表中的列的任何引用都必须使用 INSERTED 或 DELETED 前缀限定。*
    指定受删除、插入或更新操作影响的所有列都将按照它们在表中的顺序返回。例如,以下 DELETE 语句中的 OUTPUT DELETED.* 将返回 ShoppingCartItem 表中所有已删除的列: 复制代码 
    DELETE Sales.ShoppingCartItem
        OUTPUT DELETED.*;
     column_name 
    显式列引用。对要修改的表的任何引用都必须根据需要使用 INSERTED 或 DELETED 前缀加以正确限定,例如:INSERTED.column_name。$action
    仅可用于 MERGE 语句。在 MERGE 语句的 OUTPUT 子句中指定一个 nvarchar(10) 类型的列,该子句为每行返回以下三个值之一:'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 子句将始终返回语句执行之前的参数或变量的值而不是已修改的值。在使用 WHERE CURRENT OF 语法通过游标定位的 UPDATE 或 DELETE 语句中,可以使用 OUTPUT。以下语句中不支持 OUTPUT 子句:引用本地分区视图、分布式分区视图或远程表的 DML 语句。
    包含 EXECUTE 语句的 INSERT 语句。
    当数据库兼容级别设为 100 时,不允许在 OUTPUT 子句中使用全文谓词。
    不能将 OUTPUT INTO 子句插入视图或行集函数。
    如果用户定义的函数包含一个以表为目标的 OUTPUT INTO 子句,则不能创建该函数。
    若要防止出现不确定的行为,OUTPUT 子句不能包含以下引用:执行用户或系统数据访问的子查询或用户定义函数,或者被认定会执行此类访问的子查询或用户定义函数。如果用户定义函数未绑定到架构,则认定它会执行数据访问。
    视图或内嵌表值函数中的一个列(如果该列由以下方法之一定义):
    子查询。
    执行用户数据访问或系统数据访问或者被认为执行此种访问的用户定义函数。
    定义中包含执行用户数据访问或系统数据访问的用户定义函数的计算列。
    如果 SQL Server 在 OUTPUT 子句中检测到这样的列,将引发错误 4186。有关详细信息,请参阅 MSSQLSERVER_4186。
    将从 OUTPUT 子句返回的数据插入表
    在捕获嵌套的 INSERT、UPDATE、DELETE 或 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 语句生成的标识值。
    查询通知将语句作为单个实体进行处理,并且即使重大更改是来自外层 INSERT 语句本身,所创建的任何消息的类型也将是嵌套 DML 的类型。
    在 <dml_table_source> 子句中,SELECT 和 WHERE 子句不能包括子查询、聚合函数、排名函数、全文谓词、执行数据访问的用户定义函数或是 TEXTPTR 函数。
    触发器
    从 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 子句将导致该语句失败。
      

  2.   


    好问。感觉前者,使用起来更加结构合理化。但是可读性会变差。 个人感觉前者是交叉进行的, delete 一行 insert 一行。后者是 delete 全部,然后是insert 全部。
      

  3.   

    功能不同:--测试数据如下:
    if object_id('tb') is not null drop table tb
    go
    create table tb(id int, number1 int,number2 int,lan int,newid int)
    insert tb
    select 2003001,10,11,11,1 union all
    select 2003002,4,9,12,2 union all
    select 2003003,1,7,16,3 union all
    select 2003004,4,6,3,4
    go--执行这个,就删除并返回第一行
    DELETE TOP(1) dbo.tb 
    OUTPUT deleted.*
    /*
    id          number1     number2     lan         newid
    ----------- ----------- ----------- ----------- -----------
    2003001     10          11          11          1(1 行受影响)*/
    select * from tb
    /*
    id          number1     number2     lan         newid
    ----------- ----------- ----------- ----------- -----------
    2003002     4           9           12          2
    2003003     1           7           16          3
    2003004     4           6           3           4(3 行受影响)
    */