- [学习SQLSERVER2005系列]关于INSERT、UPDATE或DELETE的OUTPUT及OUTPUT...INTO...用法
- 作者:Flystone,转载注明出处
- 在INSERT、UPDATE、DELETE语句中使用OUTPUT得到语句影响的每行信息,今天我们来学习这个语法。
- 1、OUTPUT_CLAUSE定义(语法参Transact-SQL语法约定):
- <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}
- 2、OUTPUT_CLAUSE说明:
- 返回受INSERT、UPDATE或DELETE语句影响的每行的信息,或者返回基于上述每行的表达式。这些结果可以返回到处理应用程序,以供在确认消息、存档以及其他类似的应用程序要求中使用。此外,也可以将结果插入表或表变量。
- 3、典型应用:
- 1、根据当前表的数据有条件的生成历史或新的初始化数据;
- 2、把INSERT、UPDATE或DELETE语句影响的每行的信息暂存处理或反馈给应用程序完成业务或逻辑的完整性;
- 3、OUTPUT子句对于在INSERT或UPDATE操作之后检索标识列或计算列的值可能非常有用;
- 4、示列:
- 1、根据当前表的数据有条件的生成历史数据;
- 记得我以前做零售及水厂应用系统时都会有一个月未数据的处理功能,无非根据当前的数据自动生成下一个月数据的初始值。下面我以一个简化了例子来说明,例子是记录员工每个月工分变化中,我们以12月的数据生成下个月的月初数据。
- ------------------------------------
- --Author:happyflsytone
- --Date:2008-10-0216:39:39
- --Description:根据当前数据生成下个月的月初数据,并删除历史数据
- ------------------------------------
- DECLARE@sTABLE([年]INT,[月]INT,[工号]INT,[上月工分值]INT,[本月工分值]INT);
- INSERT@sSELECT2008,12,1,10,11;
- INSERT@sSELECT2008,12,2,11,12;
- INSERT@sSELECT2008,12,3,11,13;
- INSERT@sSELECT2008,12,4,3,5;
- INSERT@sSELECT2008,12,5,1,7;
- INSERT@sSELECT2008,12,6,2,11;
- DELETEFROM@s
- OUTPUTCASEWHENDELETED.[月]=12THENDELETED.[年]+1ELSEDELETED.[年]END,
- CASEWHENDELETED.[月]=12THEN1ELSEDELETED.[月]+1END,
- DELETED.[工号],DELETED.[本月工分值],NULLas[上月工分值]
- INTO@s;
- SELECT*
- FROM@s
- ORDERBY1,2,3
- /*
- 年月工号上月工分值本月工分值
- -------------------------------------------------------
- 20091111NULL
- 20091212NULL
- 20091313NULL
- 2009145NULL
- 2009157NULL
- 20091611NULL
- (6行受影响)
- */
- 2、根据业务规则的需要保证数据完整性。
- 在这个例程里我假设在更新员工的最后登录时间同时增加一条日志信息。先看测试数据:
- ------------------------------------
- --Author:happyflsytone
- --Date:2008-10-0216:39:39
- --Description:员工登录时更新员工表的最后登录时间,同时在日志表增加一条登录信息
- ------------------------------------
- --操作员信息表(本例只关心最后登录时间,所以员工的信息不深入表述)
- DECLARE@PTABLE([工号]INT,[姓名]varchar(16),[最后登录时间]datetime);
- INSERT@PSELECT1,'test1',getdate()-1;
- INSERT@PSELECT2,'test2',getdate()-1;
- INSERT@PSELECT3,'test3',getdate()-1;
- INSERT@PSELECT4,'test4',getdate()-1;
- INSERT@PSELECT5,'test5',getdate()-1;
- INSERT@PSELECT6,'test6',getdate()-1;
- --操作员操作日志(象征性列举一些字段)
- DECLARE@LOGTABLE([工号]INT,[操作时间]DATETIME,[操作类型]CHAR(6),[操作说明]VARCHAR(200));
- --模拟工号为3的操作员登录,并记录相应日志
- UPDATE@p
- SET[最后登录时间]=GETDATE()
- OUTPUTDELETED.[工号],DELETED.[最后登录时间],'出舱','成功出舱行走,身体状况良好,仪器工作正常,请主席放心!'
- INTO@log
- WHERE[工号]=3;
- --查看日志
- SELECT*
- FROM@LOG;
- /*
- 工号操作时间操作类型操作说明
- ----------------------------------------------------------------------------
- 32008-10-0117:06:58.790出舱成功出舱行走,身体状况良好,仪器工作正常,请主席放心!
- (1行受影响)
- */
- 注:其实我们可以通过这个OUTPUT_CLAUSE向应用程序提供数据操作的历史信息,或是把数据缓存在表变量中以备程序再次调用,关于这方面的例子就不多说明,因为这是最基本的OUTPUT_CLAUSE应用。
- 3、标识列或计算列方面的应用
- 对于标识列我们可能通过@@IDENTITY、SCOPE_IDENTITY和IDENT_CURRENT几个相似的函数获得,他们都返回插入到表的IDENTITY列的最后一个值(本身这几个函数还是有差异的,主要是它们的作用域,请查联机帮助)。我们注意到它们只是返回最后一个值,对于批量时就无能无力了。对于实时并发多的系统时我们可以利用OUTPUT_CLAUSE语句把标识列的值提取出来。
- ------------------------------------
- --Author:happyflsytone
- --Date:2008-10-0216:39:39
- ------------------------------------
- CREATETABLEScrapReason(scrapreasonidINTIDENTITY,[name]VARCHAR(50),modifieddateDATETIME)
- ;
- --接受标识列值的表变量
- DECLARE@MyTableVarTABLE(ScrapReasonIDSMALLINT,
- NameVARCHAR(50),
- ModifiedDateDATETIME);
- --模拟插入数据
- INSERTScrapReason
- OUTPUTINSERTED.ScrapReasonID,INSERTED.Name,INSERTED.ModifiedDate
- INTO@MyTableVar
- SELECTN'OperatorIDENTITY',GETDATE()
- FROMsys.objects;
- --查看记录的标识列数据
- SELECTScrapReasonID,Name,ModifiedDateFROM@MyTableVar;
- GO
- droptableScrapReason;
- /*
- ScrapReasonIDNameModifiedDate
- --------------------------------------------------------------------------------------
- 1OperatorIDENTITY2008-10-0217:42:19.000
- 2OperatorIDENTITY2008-10-0217:42:19.000
- 3OperatorIDENTITY2008-10-0217:42:19.000
- 4OperatorIDENTITY2008-10-0217:42:19.000
- 5OperatorIDENTITY2008-10-0217:42:19.000
- 6OperatorIDENTITY2008-10-0217:42:19.000
- .....
- .....
- 62OperatorIDENTITY2008-10-0217:42:19.000
- 63OperatorIDENTITY2008-10-0217:42:19.000
- (63行受影响)
- */
- 下面我们再来看看触发器使用OUTPUT_CLAUSE的情况,
- ------------------------------------
- --Author:happyflsytone
- --Date:2008-10-0216:39:39
- ------------------------------------
- CREATETABLETA(
- scrapreasonidINTIDENTITYPRIMARYKEY,
- [name]VARCHAR(50),
- modifieddateDATETIME
- )
- ;
- CREATETABLETB(
- IDINTREFERENCESTA(SCRAPREASONID),
- [name]VARCHAR(50),
- MODIFIEDDATEDATETIME
- );
- GO
- CREATETRIGGERTR_INSERT
- ONTA
- INSTEADOFINSERT
- AS
- BEGIN
- --接受标识列值的表变量
- DECLARE@MyTableVarTABLE(IDINT,
- [NAME]VARCHAR(10),
- ModifiedDateDATETIME);
- INSERTTA
- OUTPUTINSERTED.scrapreasonid,INSERTED.[NAME],INSERTED.ModifiedDate
- INTO@MyTableVar
- SELECT[name],modifieddateFROMINSERTED
- INSERTINTOTBSELECT*FROM@MyTableVar
- END
- GO
- --模拟插入数据
- INSERTTASELECT'TEST',GETDATE();
- INSERTTASELECT'TEST2',GETDATE();
- --查看记录的标识列数据
- SELECT*FROMTB;
- /*
- IDnameMODIFIEDDATE
- ------------------------------------------------------------------------------------
- 1TEST2008-10-0217:53:46.780
- 2TEST22008-10-0217:53:46.870
- (2行受影响)
- */
- DROPTABLETB,TA;
- 最后说明一下使用OUTPUT子句的注意事项:
- 以下语句中不支持OUTPUT子句:
- 1、引用本地分区视图、分布式分区视图或远程表的DML语句。
- 2、包含EXECUTE语句的INSERT语句。
- 3、不能将OUTPUTINTO子句插入视图或行集函数。
- 4、参数或变量作为UPDATE语句的一部分进行了修改,则OUTPUT子句将始终返回语句执行之前的参数或变量的值而不是已修改的值
- Flystone于常州
[学习SQL SERVER 2005系列]关于INSERT、UPDATE 或 DELETE的OUTPUT及OUTPUT...INTO...用法
最新推荐文章于 2023-07-13 15:48:21 发布