output是sql server2005的新特性,可以从数据修改语句中返回输出,可以看作是"返回结果的dml"。
insert、delete、update均支持output子句。
在output子句中,可以引用特殊表inserted和deleted,使用inserted和deleted表与在触发器中使用的非常相似。
在insert,delete,update中output的区别
- 对于insert,可以引用inserted表以查询新行的属性。
- 对于delete,可以引用deleted表以查询旧行的属性。
- 对于update,使用deleted表查询被更新行在更改前的属性,用inserted表标识被更新行在更改后的值。
输出方式:
- 输出给调用方(客户端应用程序)
- 输出给表
一、应用:
1、带有output的insert的应用
对于包含自增列的表执行多行insert语句,同时想知道新的标识值时,在insert中使用output子句非常方便。
1、对于单行insert语句,这不成问题:scope_identity函数即可实现。scope_identity函数:返回为当前会话和当前作用域中的任何表最后生成的标识值。
-- generating surrogate keys for customers use tempdb; go if object_id('dbo.customersdim') is not null drop table dbo.customersdim; go create table dbo.customersdim ( keycol int not null identity primary key, customerid nchar(5) not null, companyname nvarchar(40) not null, ); -- insert new customers and get their surrogate keys declare @newcusts table ( customerid nchar(5) not null primary key, keycol int not null unique ); insert into dbo.customersdim(customerid, companyname) output inserted.customerid, inserted.keycol into @newcusts -- output inserted.customerid, inserted.keycol select customerid, companyname from northwind.dbo.customers where country = n'uk'; select customerid, keycol from @newcusts; go
注意代码中被注释掉的第二个output子句,后面没有into子句。如果还要输出返回给调用方,取消注释即可。这样insert语句将包含两个output子句。
2、多行insert语句
use adventureworks; go create table testtable (id int, textval varchar(100)) declare @tmptable table (id int, textval varchar(100)) insert testtable (id, textval) output inserted.id, inserted.textval into @tmptable values (1,'firstval') insert testtable (id, textval) output inserted.id, inserted.textval into @tmptable values (2,'secondval') select * from @tmptable select * from testtable drop table testtable go
2、带有output的delete的应用.
如果要删除数据的同时,还需要记录日志,或者归档数据,在delete中使用output子句在适合不过了。
use adventureworks; go create table testtable (id int, textval varchar(100)) declare @tmptable table (id int, textval varchar(100)) insert testtable (id, textval) values (1,'firstval') insert testtable (id, textval) values (2,'secondval') delete from testtable output deleted.id, deleted.textval into @tmptable where id in (1,2) select * from @tmptable select * from testtable drop table testtable go
3、带有output的update的应用
use adventureworks; go create table testtable (id int, textval varchar(100)) declare @tmptable table (id_new int, textval_new varchar(100),id_old int, textval_old varchar(100)) insert testtable (id, textval) values (1,'firstval') insert testtable (id, textval) values (2,'secondval') update testtable set textval = 'newvalue' output inserted.id, inserted.textval, deleted.id, deleted.textval into @tmptable where id in (1,2) select * from @tmptable select * from testtable drop table testtable go
4、在 update 语句中使用包含 from_table_name 的 output into
以下示例使用指定的 productid
和 scrapreasonid
,针对 workorder
表中的所有工作顺序更新 scrapreasonid
列。
output into
子句返回所更新表 (workorder
) 中的值以及 product
表中的值。 在 product
子句中使用 from
表来指定要更新的行。
由于 workorder
表上定义了 after update
触发器,因此需要 into
关键字。
use adventureworks2012; go declare @mytestvar table ( oldscrapreasonid int not null, newscrapreasonid int not null, workorderid int not null, productid int not null, productname nvarchar(50)not null); update production.workorder set scrapreasonid = 4 output deleted.scrapreasonid, inserted.scrapreasonid, inserted.workorderid, inserted.productid, p.name into @mytestvar from production.workorder as wo inner join production.product as p on wo.productid = p.productid and wo.scrapreasonid= 16 and p.productid = 733; select oldscrapreasonid, newscrapreasonid, workorderid, productid, productname from @mytestvar; go
4、merge语句
下面的示例捕获从 output
语句的 merge
子句返回的数据,并将这些数据插入另一个表。
merge
语句每天根据在 quantity
表中处理的订单更新 productinventory
表的 salesorderdetail
列。 如果产品的库存降至 0
或更低,它还会删除与这些产品对应的行。
本示例捕获已删除的行并将这些行插入另一个表 zeroinventory
中,该表跟踪没有库存的产品。
use adventureworks2012; go if object_id(n'production.zeroinventory', n'u') is not null drop table production.zeroinventory; go --create zeroinventory table. create table production.zeroinventory (deletedproductid int, removedondate datetime); go insert into production.zeroinventory (deletedproductid, removedondate) select productid, getdate() from ( merge production.productinventory as pi using (select productid, sum(orderqty) from sales.salesorderdetail as sod join sales.salesorderheader as soh on sod.salesorderid = soh.salesorderid and soh.orderdate = '20070401' group by productid) as src (productid, orderqty) on (pi.productid = src.productid) when matched and pi.quantity - src.orderqty <= 0 then delete when matched then update set pi.quantity = pi.quantity - src.orderqty output $action, deleted.productid) as changes (action, productid) where action = 'delete'; if @@rowcount = 0 print 'warning: no rows were inserted'; go select deletedproductid, removedondate from production.zeroinventory;
二、使用output子句的注意事项:
以下语句中不支持 output 子句:
- 引用本地分区视图、分布式分区视图或远程表的 dml 语句。
- 包含 execute 语句的 insert 语句。
- 不能将 output into 子句插入视图或行集函数。
- 参数或变量作为 update 语句的一部分进行了修改,则 output 子句将始终返回语句执行之前的参数或变量的值而不是已修改的值
三、c#中使用cmd.executescalar(单列)、cmdexecutereader(多行或多列)
返回单列:
using(sqlcommand cmd=new sqlcommand("insert into mem_basic(mem_na,mem_occ) output inserted.id values(@na,@occ)",con)) { cmd.parameters.addwithvalue("@na", mem_na); cmd.parameters.addwithvalue("@occ", mem_occ); con.open(); int modified =(int)cmd.executescalar(); if (con.state == system.data.connectionstate.open) con.close(); return modified; }
返回多行或者多列:
create table suspension (pkey int not null identity(1, 1), pallet_position int, processing_pallet_pkey int, datetime_created datetime, datetime_updated datetime, [this.created_by] int, [this.updated_by] int); using (var conn = new sqlconnection(connectionstring)) { conn.open(); const string insertquery = @" insert into dbo.suspension (pallet_position, processing_pallet_pkey, datetime_created, datetime_updated, [this.created_by], [this.updated_by]) output inserted.pkey values (1, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), (2, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), (3, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2), (4, 2, '20141013 16:27:25.000', '20141013 16:27:25.000', 2, 2);"; // 通过数据库 datatable dt = new datatable(); using (sqlcommand cmd = new sqlcommand(insertquery, conn)) using (var insertedoutput = cmd.executereader()) { dt.load(insertedoutput); } console.writeline(dt.rows.count); // 4 // 通过手工读取 var list = new list<int>(); using (sqlcommand cmd = new sqlcommand(insertquery, conn)) using (var insertedoutput = cmd.executereader()) { while(insertedoutput.read()) { list.add(insertedoutput.getint32(0)); } } console.writeline(list.count); // 4 // 通过dapper var ids = conn.query<int>(insertquery).tolist(); console.writeline(ids.count); // 4 }
四、参考:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持代码网。
发表评论