update from (view)更新表的条件是一个查询
update ... from (view)语句更新表的条件是一个查询集
以下操作就是基于oracle,先来说一个常见的update操作
假设表T1,T2,T3,......
表T1有主键T1_PK1,T1_PK2,
表T2有主键T2_PK
首先我们这个比较常用
update T2
set T2.col1 = value
where T2.T2_PK = value;
这个sql的更新语句很常见很基础,但是很多情况下更新的条件不是已知的,需要一个查询来确定,这时候就可以这样写上面的语句了
update T2
set T2.col1 = value
where T2.T2_PK in
(
--T3.T3_PK和T2.T2_PK是相同的字段
select T3.T3_PK
from T3,T4,T5
--这里写查询的条件
--where .....
)
这个是单主键表的更新,用一个主键可以确定唯一的数据,但是在多主键中多个主键唯一确定一条数据,这样要更新一条主键唯一标识的数据上面的写法肯定不行。这时候可以利用下面的这种写法:
update T1
set T1.col = value
where T1.T1_PK1 in
(
select
T2.T2_PK,--和T1_PK1是相同的字段
T4.T4_PK --和T1_PK2是相同的字段
from T2,T3,T4,T5
where .........--各种条件
and T1.T1_PK2 = T4.T4_PK --这样就算是和查询结果连接起来的,数据没有多余
);
这个是我写的,是标准的sql,但是感觉比较晦涩,回来问了一下别人,有人告诉我一个方法是下面的,不过我没有试行不行,明天试试
update T1
set T1.col = value
where (T1.T1_PK1,T1.T1_PK2) =
(
select
T2.T2_PK,--和T1_PK1是相同的字段
T4.T4_PK --和T1_PK2是相同的字段
from T2,T3,T4,T5
where .........--各种条件
);
这个写法看起来优雅潇洒,简单明白,这个方法我试过之后发现也有个不足,就是=后面的结果只能是单行,如果查询结果是多行的时候把=换成in就可以了。
下面还有几种容易出错或者麻烦的写法
比如这样写
update T1
set T1.col = value
where T1.T1_PK1 in
(
select
T2.T2_PK,--和T1_PK1是相同的字段
T4.T4_PK --和T1_PK2是相同的字段
from T2,T3,T4,T5
where .........--各种条件
)
and T1.T1_PK2 in
(
select
T2.T2_PK,--和T1_PK1是相同的字段
T4.T4_PK --和T1_PK2是相同的字段
from T2,T3,T4,T5
where .........--各种条件
);
这样写很明显,但是其实是错误的,会更新掉你不希望更新的数据,因为T1_PK1 和T1_PK12唯一标识一条数据,上面的更新会更新许多数据,数据不是T1_PK1和T1_PK2的组合,而是判断T1_PK1和T1_PK2是否存在查询结果中。
还有一种写法
update (
select
T1.T1_PK1,--和T1_PK1是相同的字段
T1.T2_PK2 --和T1_PK2是相同的字段
from T1,T2,T3,T4,T5
where .........--各种条件
)
set T1.col = value;
这样也就是网上很多人说的方法,这个方法其实就是更新视图(view),这个方法很容易出错“无法修改与非键值保存表对应的列”,为什么会出现这个错误呢,是因为在查询的视图中用了非主键的连接,这样得出的视图是无法唯一标识数据的,所以更新的时候会出现错误。要避免就需要单独建立一个view,并且设置主键就可以了,但是就为了一个sql中更新一下数据,以后也不常用,为什么要建立一个view呢,如果是大的项目中,遍地的view以后维护的人要被搞死了。
当然t-sql中很简单,有个update from语句,这样就不用这么麻烦了,但是这个语句不是sql标准语句。正如oracle的decode语句一样,换个地方就不行了。所以写的时候尽量用sql标准来写,万一有一天系统迁移的时候能剩不少事情。