update od set discount +=0.05from dbo.orderdetails as od
join dbo.orders as o
on od.orderid = o.orderid
where custid =1;
ANSI实现
update dbo.orderdetails set discount +=0.05whereexists(select*from dbo.orders as o
where o.orderid = orderdetails.orderid
and custid =1);
8.3.2.2 作为赋值来源
T-SQL实现
update T1
set col1 = T2.col1,
col2 = T2.col2,
col3 = T2.col3
from dbo.T1 join dbo.T2
on T1.keycol = T2.keycol
where T2.col4 ='ABC';
ANSI实现
update dbo.T1
set col1 =(select col1
from dbo.T2
where T2.keycol = T1.keycol),set col2 =(select col2
from dbo.T2
where T2.keycol = T1.keycol),set col3 =(select col3
from dbo.T2
where T2.keycol = T1.keycol),whereexists(select*from dbo.T2
where T2.keycol = T1.keycol
and T2.col4 ='ABC');
SQL Server2008中尚未实现的行构造函数-ANSI
update dbo.T1
set(col1,col2,col3)=(select col1,col2,col3
from dbo.T2
where T2.keycol = T1.keycol)whereexists(select*from dbo.T2
where T2.keycol = T1.keycol
and T2.col4 ='ABC');
8.3.3 赋值update
T-SQL
在对表中的数据进行更新的同时为变量赋值
原子操作
declare@nextvalasint;update sequence set@nextval= val = val +1;
常用场景
自增标识列无法满足需求,需要维护自定义编号机制
自定义编号机制中
将当前编号保存在一个表中
当需要插入新数据时
在插入之前,先更新当前编号 +1
同时获取更新后的当前编号作为新数据的编号进行插入操作
8.4 合并数据
ANSI
作用
在一条语句中根据逻辑条件对数据进行不同的修改操作
insert、update、delete
例如,用来源表的数据更新目标表
对目标表中已经存在了的数据,执行更新操作
也可以增加逻辑条件
当数据不一致时才执行更新操作
对目标表中尚不存在的数据,执行插入操作
对来源表中不存在但在目标表中存在的数据,执行删除操作
T-SQL
mergeinto dbo.customers as tgt
using dbo.customersstage as src
on tgt.custid = src.custid
whenmatchedand(tgt.companyname <> src.companyname or
tgt.phone <> src.phone or
tgt.address <> src.address)thenupdateset
tgt.companyname = src.companyname,
tgt.phone = src.phone,
tgt.address = src.address
whennotmatchedtheninsert(custid,companyname,phone,address)values(src.custid,src.companyname,src.phone,src.address)whennotmatchedby source thendelete;
8.5 通过表表达式修改数据
表表达式虽然不是实际存在的表,但对表表达式的结果进行修改,能转化为对基础表的数据的修改
8.5.1 转化为基础表的数据修改的条件
如果表表达式需要联接多表,则同一修改语句中的修改只能影响联接的一边,不能同时影响两边
不能对作为计算结果的列进行更新
当需要通过表表达式插入新行时,如果部分列没有赋值且没有默认值,则无法成功
update od set discount = discount +0.05from dbo.orderdetails as od
join dbo.orders as o
on od.orderid = o.orderid
where custid =1
8.5.2 简化调试
对于在更新之前想先看看update语句将要修改哪些行的情况
如果不使用表表达式
则需要先将update改为select
查询出将要修改的数据行,再切换回update
使用表表达式进行update
不需要在select和update之间来回切换
with c as(select custid,od.orderid,productid,discount
from dbo.orderdetails as od
join dbo.orders as o
on od.orderid = o.orderid
where custid =1)update c set discount = discount +0.05;
8.5.3 避开限制
例如,在update语句中不允许使用row_number()函数
使用表表达式,可以先生成row_number(),再将结果作为数据来源进行赋值修改
with c as(select col1,col2
,row_number()over(orderby col1)as rownum
from dbo.t1
)update c set col2 = rownum;
8.6 带有top选项的数据更新
在insert、update、delete以及merge语句中允许使用top选项
当处理的行数达到指定数据或百分比时,将停止执行修改语句
例如,update top(50) dbo.orders set freight = freight + 10.00;
但无法保证修改的顺序
因为无法为修改语句指定order by
可以借助表表达式,先将需要修改的数据行查询出来再进行修改
with c as(selecttop(50)*from dbo.orders
orderby orderid desc)update c set freight +=10.00;
declare@newrowstable(keycol int,datacol nvarchar(40));insertinto dbo.t1(datacol)
output inserted.keycol,inserted.datecol
into@newrowsselect lastname
from hr.employees
where country ='UK';
8.7.2 带有output的delete语句
deletefrom dbo.orders
output
deleted.orderid,
deleted.orderdate,
deleted.empid,
deleted.custid
where orderdate <'20080101';
8.7.3 带有output的update语句
update dbo.orderdetails
set discount +=0.05
output
inserted.productid,
deleted.discount as olddiscount,
inserted.discount as newdiscount
where productid =51;
8.7.4 带有output的merge语句
$action
返回代表相应操作的字符串,如“update"
mergeinto dbo.customers as tgt
using dbo.customersstage as src
on tgt.custid = src.custid
whenmatchedand(tgt.companyname <> src.companyname or
tgt.phone <> src.phone or
tgt.address <> src.address)thenupdateset
tgt.companyname = src.companyname,
tgt.phone = src.phone,
tgt.address = src.address
whennotmatchedtheninsert(custid,companyname,phone,address)values(src.custid,src.companyname,src.phone,src.address)
output $action,inserted.custid,
deleted.companyname as oldcompanyname,
inserted.companyname as newcompanyname,
deleted.phone as oldphone,
inserted.phone as newphone,
deleted.address as oldaddress,
inserted.address as newaddress;
insertinto dbo.productsaudit(productid,colname
,oldval,newval)select productid,unitprice,oldval,newval
from(update dbo.products
set unitprice *=1.15
output
inserted.productid,
deleted.unitprice as oldval,
inserted.unitprice as newval
where supplierid =1)as d
where oldval <20.0and newval>=20.0;