[学习SQL SERVER 2005系列]关于INSERT、UPDATE 或 DELETE的OUTPUT及OUTPUT...INTO...用法

  1. [学习SQL SERVER 2005系列]关于INSERT、UPDATE 或 DELETE的OUTPUT及OUTPUT...INTO...用法
  2.      作者:Flystone ,转载注明出处
  3.     在INSERT、UPDATE、DELETE语句中使用OUTPUT得到语句影响的每行信息,今天我们来学习这个语法。
  4. 1、OUTPUT_CLAUSE定义(语法参Transact-SQL 语法约定):
  5. <OUTPUT_CLAUSE> ::=
  6. {
  7.     [ OUTPUT <dml_select_list> INTO { @table_variable | output_table } [ ( column_list ) ] ]
  8.     [ OUTPUT <dml_select_list> ]
  9. }
  10. <dml_select_list> ::=
  11. { <column_name> | scalar_expression } [ [AS] column_alias_identifier ]
  12.     [ ,...n ]
  13. <column_name> ::=
  14. { DELETED | INSERTED | from_table_name } . { * | column_name }
  15. 2、OUTPUT_CLAUSE说明:
  16.     返回受 INSERT、UPDATE 或 DELETE 语句影响的每行的信息,或者返回基于上述每行的表达式。这些结果可以返回到处理应用程序,以供在确认消息、存档以及其他类似的应用程序要求中使用。此外,也可以将结果插入表或表变量。
  17. 3、典型应用:
  18.     1、根据当前表的数据有条件的生成历史或新的初始化数据;
  19.     2、把INSERT、UPDATE 或 DELETE 语句影响的每行的信息暂存处理或反馈给应用程序完成业务或逻辑的完整性;
  20.     3、OUTPUT 子句对于在 INSERT 或 UPDATE 操作之后检索标识列或计算列的值可能非常有用;
  21. 4、示列:
  22.     1、根据当前表的数据有条件的生成历史数据;
  23.     记得我以前做零售及水厂应用系统时都会有一个月未数据的处理功能,无非根据当前的数据自动生成下一个月数据的初始值。下面我以一个简化了例子来说明,例子是记录员工每个月工分变化中,我们以12月的数据生成下个月的月初数据。
  24. ------------------------------------
  25. -- Author:  happyflsytone  
  26. -- Date:2008-10-02 16:39:39
  27. -- Description:根据当前数据生成下个月的月初数据,并删除历史数据
  28. ------------------------------------    
  29. DECLARE  @s TABLE([年] INT,[月] INT,[工号] INT,[上月工分值] INT,[本月工分值] INT);
  30. INSERT @s SELECT 2008,12,1,10,11;
  31. INSERT @s SELECT 2008,12,2,11,12;
  32. INSERT @s SELECT 2008,12,3,11,13;
  33. INSERT @s SELECT 2008,12,4,3,5;
  34. INSERT @s SELECT 2008,12,5,1,7;
  35. INSERT @s SELECT 2008,12,6,2,11;
  36. DELETE FROM  @s
  37. OUTPUT CASE WHEN DELETED.[月] = 12 THEN DELETED.[年]+ 1 ELSE DELETED.[年] END  ,
  38.        CASE WHEN DELETED.[月] = 12 THEN 1 ELSE DELETED.[月] + 1 END ,
  39.        DELETED.[工号],DELETED.[本月工分值],NULL as [上月工分值]
  40. INTO @s;
  41. SELECT * 
  42. FROM @s
  43. ORDER BY 1,2,3
  44. /*
  45. 年           月           工号          上月工分值       本月工分值
  46. ----------- ----------- ----------- ----------- -----------
  47. 2009        1           1           11          NULL
  48. 2009        1           2           12          NULL
  49. 2009        1           3           13          NULL
  50. 2009        1           4           5           NULL
  51. 2009        1           5           7           NULL
  52. 2009        1           6           11          NULL
  53. (6 行受影响)
  54. */
  55.     2、根据业务规则的需要保证数据完整性。
  56.     在这个例程里我假设在更新员工的最后登录时间同时增加一条日志信息。先看测试数据:
  57. ------------------------------------
  58. -- Author:  happyflsytone  
  59. -- Date:2008-10-02 16:39:39
  60. -- Description:员工登录时更新员工表的最后登录时间,同时在日志表增加一条登录信息
  61. ------------------------------------    
  62. -- 操作员信息表(本例只关心最后登录时间,所以员工的信息不深入表述)
  63. DECLARE  @P TABLE([工号] INT,[姓名] varchar(16),[最后登录时间] datetime);
  64. INSERT @P SELECT 1,'test1',getdate() - 1;
  65. INSERT @P SELECT 2,'test2',getdate() - 1;
  66. INSERT @P SELECT 3,'test3',getdate() - 1;
  67. INSERT @P SELECT 4,'test4',getdate() - 1;
  68. INSERT @P SELECT 5,'test5',getdate() - 1;
  69. INSERT @P SELECT 6,'test6',getdate() - 1;
  70. -- 操作员操作日志(象征性列举一些字段)
  71. DECLARE @LOG TABLE([工号] INT,[操作时间] DATETIME,[操作类型] CHAR(6),[操作说明] VARCHAR(200));
  72. --模拟工号为3的操作员登录,并记录相应日志
  73. UPDATE @p
  74. SET [最后登录时间] = GETDATE() 
  75. OUTPUT DELETED.[工号],DELETED.[最后登录时间],'出舱','成功出舱行走,身体状况良好,仪器工作正常,请主席放心!'
  76. INTO @log
  77. WHERE [工号] = 3;
  78. -- 查看日志
  79. SELECT * 
  80. FROM @LOG;
  81. /*
  82. 工号          操作时间                    操作类型   操作说明
  83. ----------- ----------------------- ------ ------------------------------------
  84. 3           2008-10-01 17:06:58.790 出舱     成功出舱行走,身体状况良好,仪器工作正常,请主席放心!
  85. (1 行受影响)
  86. */
  87.     注:其实我们可以通过这个OUTPUT_CLAUSE向应用程序提供数据操作的历史信息,或是把数据缓存在表变量中以备程序再次调用,关于这方面的例子就不多说明,因为这是最基本的OUTPUT_CLAUSE应用。
  88.     
  89.     3、标识列或计算列方面的应用
  90.     对于标识列我们可能通过@@IDENTITY、SCOPE_IDENTITY 和 IDENT_CURRENT 几个相似的函数获得,他们都返回插入到表的 IDENTITY 列的最后一个值(本身这几个函数还是有差异的,主要是它们的作用域,请查联机帮助)。我们注意到它们只是返回最后一个值,对于批量时就无能无力了。对于实时并发多的系统时我们可以利用OUTPUT_CLAUSE语句把标识列的值提取出来。
  91.     
  92. ------------------------------------
  93. -- Author:  happyflsytone  
  94. -- Date:2008-10-02 16:39:39
  95. ------------------------------------
  96. CREATE TABLE ScrapReason(scrapreasonid INT IDENTITY,[name] VARCHAR(50),modifieddate DATETIME)
  97. ;
  98. --接受标识列值的表变量
  99. DECLARE @MyTableVar TABLE( ScrapReasonID SMALLINT,
  100.                            Name VARCHAR(50),
  101.                            ModifiedDate DATETIME);
  102. --模拟插入数据
  103. INSERT ScrapReason
  104.     OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
  105.         INTO @MyTableVar
  106. SELECT N'Operator IDENTITY', GETDATE()
  107. FROM sys.objects ;
  108. --查看记录的标识列数据
  109. SELECT ScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
  110. GO
  111. drop table ScrapReason;
  112. /*
  113. ScrapReasonID Name                                               ModifiedDate
  114. ------------- -------------------------------------------------- -----------------------
  115. 1             Operator IDENTITY                                  2008-10-02 17:42:19.000
  116. 2             Operator IDENTITY                                  2008-10-02 17:42:19.000
  117. 3             Operator IDENTITY                                  2008-10-02 17:42:19.000
  118. 4             Operator IDENTITY                                  2008-10-02 17:42:19.000
  119. 5             Operator IDENTITY                                  2008-10-02 17:42:19.000
  120. 6             Operator IDENTITY                                  2008-10-02 17:42:19.000
  121. .....
  122. .....
  123. 62            Operator IDENTITY                                  2008-10-02 17:42:19.000
  124. 63            Operator IDENTITY                                  2008-10-02 17:42:19.000
  125. (63 行受影响)
  126. */
  127.     
  128.     下面我们再来看看触发器使用OUTPUT_CLAUSE的情况,
  129.     
  130. ------------------------------------
  131. -- Author:  happyflsytone  
  132. -- Date:2008-10-02 16:39:39
  133. ------------------------------------
  134. CREATE TABLE TA(
  135.   scrapreasonid INT IDENTITY PRIMARY KEY,
  136.   [name] VARCHAR(50),
  137.   modifieddate DATETIME
  138. )
  139. ;
  140. CREATE TABLE TB(
  141.   ID INT REFERENCES TA(SCRAPREASONID),
  142.   [name] VARCHAR(50),
  143.   MODIFIEDDATE DATETIME
  144. );
  145. GO
  146. CREATE TRIGGER TR_INSERT
  147. ON TA
  148. INSTEAD OF INSERT
  149. AS
  150. BEGIN
  151.     --接受标识列值的表变量
  152.     DECLARE @MyTableVar TABLE( ID INT,
  153.                                [NAME] VARCHAR(10),
  154.                                ModifiedDate DATETIME);
  155.     INSERT TA
  156.         OUTPUT INSERTED.scrapreasonid,INSERTED.[NAME],INSERTED.ModifiedDate
  157.             INTO @MyTableVar
  158.     SELECT [name],modifieddate FROM INSERTED
  159.     INSERT INTO TB SELECT * FROM @MyTableVar
  160. END
  161. GO
  162. --模拟插入数据
  163. INSERT TA SELECT 'TEST',GETDATE();
  164. INSERT TA SELECT 'TEST2',GETDATE();
  165. --查看记录的标识列数据
  166. SELECT * FROM TB;
  167. /*
  168. ID          name                                               MODIFIEDDATE
  169. ----------- -------------------------------------------------- -----------------------
  170. 1           TEST                                               2008-10-02 17:53:46.780
  171. 2           TEST2                                              2008-10-02 17:53:46.870
  172. (2 行受影响)
  173. */
  174. DROP TABLE TB,TA;
  175.     最后说明一下使用OUTPUT子句的注意事项:
  176.     以下语句中不支持 OUTPUT 子句:
  177.     1、引用本地分区视图、分布式分区视图或远程表的 DML 语句。 
  178.     2、包含 EXECUTE 语句的 INSERT 语句。
  179.     3、不能将 OUTPUT INTO 子句插入视图或行集函数。
  180.     4、参数或变量作为 UPDATE 语句的一部分进行了修改,则 OUTPUT 子句将始终返回语句执行之前的参数或变量的值而不是已修改的值
  181.                           Flystone  于常州

你可能感兴趣的:(sql,server,null,delete,insert,sqlserver,output)