SQL Server--OUTPUT及OUTPUT...INTO... 在 INSERT、UPDATE 或 DELETE的用法


在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-02 16:39:39
-- Description:根据当前数据生成下个月的月初数据,并删除历史数据
------------------------------------    
DECLARE  @s TABLE([年] INT,[月] INT,[工号] INT,[上月工分值] INT,[本月工分值] INT);
INSERT @s SELECT 2008,12,1,10,11;
INSERT @s SELECT 2008,12,2,11,12;
INSERT @s SELECT 2008,12,3,11,13;
INSERT @s SELECT 2008,12,4,3,5;
INSERT @s SELECT 2008,12,5,1,7;
INSERT @s SELECT 2008,12,6,2,11;
DELETE FROM  @s
OUTPUT CASE WHEN DELETED.[月] = 12 THEN DELETED.[年]+ 1 ELSE DELETED.[年] END  ,
       CASE WHEN DELETED.[月] = 12 THEN 1 ELSE DELETED.[月] + 1 END ,
       DELETED.[工号],DELETED.[本月工分值],NULL as [上月工分值]
INTO @s;
SELECT * 
FROM @s
ORDER BY 1,2,3
/*
年           月           工号          上月工分值       本月工分值
----------- ----------- ----------- ----------- -----------
2009        1           1           11          NULL
2009        1           2           12          NULL
2009        1           3           13          NULL
2009        1           4           5           NULL
2009        1           5           7           NULL
2009        1           6           11          NULL
(6 行受影响)
*/
    2、根据业务规则的需要保证数据完整性。
    在这个例程里我假设在更新员工的最后登录时间同时增加一条日志信息。先看测试数据:
------------------------------------
-- Author:  happyflsytone  
-- Date:2008-10-02 16:39:39
-- Description:员工登录时更新员工表的最后登录时间,同时在日志表增加一条登录信息
------------------------------------    
-- 操作员信息表(本例只关心最后登录时间,所以员工的信息不深入表述)
DECLARE  @P TABLE([工号] INT,[姓名] varchar(16),[最后登录时间] datetime);
INSERT @P SELECT 1,'test1',getdate() - 1;
INSERT @P SELECT 2,'test2',getdate() - 1;
INSERT @P SELECT 3,'test3',getdate() - 1;
INSERT @P SELECT 4,'test4',getdate() - 1;
INSERT @P SELECT 5,'test5',getdate() - 1;
INSERT @P SELECT 6,'test6',getdate() - 1;
-- 操作员操作日志(象征性列举一些字段)
DECLARE @LOG TABLE([工号] INT,[操作时间] DATETIME,[操作类型] CHAR(6),[操作说明] VARCHAR(200));
--模拟工号为3的操作员登录,并记录相应日志
UPDATE @p
SET [最后登录时间] = GETDATE() 
OUTPUT DELETED.[工号],DELETED.[最后登录时间],'出舱','成功出舱行走,身体状况良好,仪器工作正常,请主席放心!'
INTO @log
WHERE [工号] = 3;
-- 查看日志
SELECT * 
FROM @LOG;
/*
工号          操作时间                    操作类型   操作说明
----------- ----------------------- ------ ------------------------------------
3           2008-10-01 17:06:58.790 出舱     成功出舱行走,身体状况良好,仪器工作正常,请主席放心!
(1 行受影响)
*/
    注:其实我们可以通过这个OUTPUT_CLAUSE向应用程序提供数据操作的历史信息,或是把数据缓存在表变量中以备程序再次调用,关于这方面的例子就不多说明,因为这是最基本的OUTPUT_CLAUSE应用。
    
    3、标识列或计算列方面的应用
    对于标识列我们可能通过@@IDENTITY、SCOPE_IDENTITY 和 IDENT_CURRENT 几个相似的函数获得,他们都返回插入到表的 IDENTITY 列的最后一个值(本身这几个函数还是有差异的,主要是它们的作用域,请查联机帮助)。我们注意到它们只是返回最后一个值,对于批量时就无能无力了。对于实时并发多的系统时我们可以利用OUTPUT_CLAUSE语句把标识列的值提取出来。
    
------------------------------------
-- Author:  happyflsytone  
-- Date:2008-10-02 16:39:39
------------------------------------
CREATE TABLE ScrapReason(scrapreasonid INT IDENTITY,[name] VARCHAR(50),modifieddate DATETIME)
;
--接受标识列值的表变量
DECLARE @MyTableVar TABLE( ScrapReasonID SMALLINT,
                           Name VARCHAR(50),
                           ModifiedDate DATETIME);
--模拟插入数据
INSERT ScrapReason
    OUTPUT INSERTED.ScrapReasonID, INSERTED.Name, INSERTED.ModifiedDate
        INTO @MyTableVar
SELECT N'Operator IDENTITY', GETDATE()
FROM sys.objects ;
--查看记录的标识列数据
SELECT ScrapReasonID, Name, ModifiedDate FROM @MyTableVar;
GO
drop table ScrapReason;
/*
ScrapReasonID Name                                               ModifiedDate
------------- -------------------------------------------------- -----------------------
1             Operator IDENTITY                                  2008-10-02 17:42:19.000
2             Operator IDENTITY                                  2008-10-02 17:42:19.000
3             Operator IDENTITY                                  2008-10-02 17:42:19.000
4             Operator IDENTITY                                  2008-10-02 17:42:19.000
5             Operator IDENTITY                                  2008-10-02 17:42:19.000
6             Operator IDENTITY                                  2008-10-02 17:42:19.000
.....
.....
62            Operator IDENTITY                                  2008-10-02 17:42:19.000
63            Operator IDENTITY                                  2008-10-02 17:42:19.000
(63 行受影响)
*/
    
    下面我们再来看看触发器使用OUTPUT_CLAUSE的情况,
    
------------------------------------
-- Author:  happyflsytone  
-- Date:2008-10-02 16:39:39
------------------------------------
CREATE TABLE TA(
  scrapreasonid INT IDENTITY PRIMARY KEY,
  [name] VARCHAR(50),
  modifieddate DATETIME
)
;
CREATE TABLE TB(
  ID INT REFERENCES TA(SCRAPREASONID),
  [name] VARCHAR(50),
  MODIFIEDDATE DATETIME
);
GO
CREATE TRIGGER TR_INSERT
ON TA
INSTEAD OF INSERT
AS
BEGIN
    --接受标识列值的表变量
    DECLARE @MyTableVar TABLE( ID INT,
                               [NAME] VARCHAR(10),
                               ModifiedDate DATETIME);
    INSERT TA
        OUTPUT INSERTED.scrapreasonid,INSERTED.[NAME],INSERTED.ModifiedDate
            INTO @MyTableVar
    SELECT [name],modifieddate FROM INSERTED
    INSERT INTO TB SELECT * FROM @MyTableVar
END
GO
--模拟插入数据
INSERT TA SELECT 'TEST',GETDATE();
INSERT TA SELECT 'TEST2',GETDATE();
--查看记录的标识列数据
SELECT * FROM TB;
/*
ID          name                                               MODIFIEDDATE
----------- -------------------------------------------------- -----------------------
1           TEST                                               2008-10-02 17:53:46.780
2           TEST2                                              2008-10-02 17:53:46.870
(2 行受影响)
*/
DROP TABLE TB,TA;
    最后说明一下使用OUTPUT子句的注意事项:
    以下语句中不支持 OUTPUT 子句:
    1、引用本地分区视图、分布式分区视图或远程表的 DML 语句。 
    2、包含 EXECUTE 语句的 INSERT 语句。
    3、不能将 OUTPUT INTO 子句插入视图或行集函数。
    4、参数或变量作为 UPDATE 语句的一部分进行了修改,则 OUTPUT 子句将始终返回语句执行之前的参数或变量的值而不是已修改的值

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值