您的位置:首页 > 数据库 > SQL

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

2008-10-05 15:14 597 查看
[学习SQL SERVER 2005系列]关于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-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 子句将始终返回语句执行之前的参数或变量的值而不是已修改的值

Flystone 于常州
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐