ORACLE 关连更新 update select

总结:  关键的地方是where 语句的加入. 在11G中, 如果不加11G , 或造成除匹配的行数更新为相应的值之后, 其余的会变成负数.

所以, 测试的办法就是:  先查看需要更新的数量即连接的数量究竟有多少行, 然后update 之后多少行, 才能确定条件是否正确.

引入知识比较全面的地址:

http://www.blogjava.net/Jhonney/archive/2010/06/25/324503.html.  文章最后注明转载.

本人用到的2处SQL:

1 :

  1. UPDATE SFISM4.R_DT_DIP_TRACEABILITY_T B
  2. SET (B.CURRENT_QTY, B.UPDATE_TIME, B.UPDATE_USER)=
  3. (SELECT DECODE(SIGN(B.CURRENT_QTY - A.KP_COUNT),
  4. -1,
  5. 0,
  6. B.CURRENT_QTY - A.KP_COUNT),
  7. SYSDATE,
  8. :VUSER
  9. FROM SFIS1.C_DT_DIP_BOM_T A, SFISM4.R_MO_BASE_T C
  10. WHERE A.BOM_NO = B.BOM_NO
  11. AND B.BOM_NO = C.KEY_PART_NO
  12. AND A.KEY_PART_NO = B.KEY_PART_NO
  13. AND C.MO_NUMBER =:VBOM
  14. AND B.TRAC_LOT =:VTRACELOT)
  15. WHERE B.TRAC_LOT =:VTRACELOT
  16. AND EXISTS (SELECT 1
  17. FROM SFIS1.C_DT_DIP_BOM_T AA
  18. WHERE B.BOM_NO = AA.BOM_NO
  19. AND B.KEY_PART_NO = AA.KEY_PART_NO)
  20. UPDATE SFISM4.R_REEL_TRACKING_T A
  21. SET A.REMAIN_QTY =
  22. (SELECT B.REEL_QTY
  23. FROM SFISM4.R_MMS_STOCK_SMT_SA_DETAIL_T B
  24. WHERE A.REEL_ID = B.REEL_ID
  25. AND A.REMAIN_QTY <0
  26. AND A.REMAIN_QTY <> B.REEL_QTY)
  27. WHERE EXISTS (SELECT 1
  28. FROM SFISM4.R_MMS_STOCK_SMT_SA_DETAIL_T B
  29. WHERE A.REEL_ID = B.REEL_ID
  30. AND A.REMAIN_QTY <0
  31. AND A.REMAIN_QTY <> B.REEL_QTY);

2:

  1. UPDATE SFISM4.R_REEL_TRACKING_T A
  2. SET A.REMAIN_QTY =
  3. (SELECT B.REEL_QTY
  4. FROM SFISM4.R_MMS_STOCK_SMT_SA_DETAIL_T B
  5. WHERE A.REEL_ID = B.REEL_ID
  6. AND A.REMAIN_QTY <0
  7. AND A.REMAIN_QTY <> B.REEL_QTY)
  8. WHERE EXISTS (SELECT 1
  9. FROM SFISM4.R_MMS_STOCK_SMT_SA_DETAIL_T B
  10. WHERE A.REEL_ID = B.REEL_ID
  11. AND A.REMAIN_QTY <0
  12. AND A.REMAIN_QTY <> B.REEL_QTY);

最后是引用比较好的说明如下, 进行标注: 原文网址: http://www.blogjava.net/Jhonney/archive/2010/06/25/324503.html

SQL> select * from wwm2;        --要更新的表 , 多一点.

TOWN                         ID
-------------------- ----------
222                         222
111                         111
ww‘jj                       111
llll                       1111
dddd                       2222
lllldf                      111
lllldf                      111
dsafdf                      111
3435                        111
ljjjjj                      222
dsafdf                      111

TOWN                         ID
-------------------- ----------
3435                        111
ljjjjj                      222

SQL> select * from wwm5;            --更新的条件表 , 少一点

TOWN                         ID
-------------------- ----------
lllldf                      111
test                       9984

SQL> select wwm2.* from wwm2,wwm5 where wwm2.id=wwm5.id
  2  /

TOWN                         ID
-------------------- ----------
111                         111
ww‘jj                       111
lllldf                      111
lllldf                      111
dsafdf                      111
3435                        111
dsafdf                      111
3435                        111

8 rows selected.

所以,每次需要更新8条数据就是正确的. 这一步是验证更新是不是对, 错的关键.!!!

相信程序员是通过以下类似的SQL更新的,这是错误的,因为没有加WHERE
SQL>  update wwm2 set wwm2.town=(select wwm5.town from wwm5 where wwm5.id=wwm2.id)
  2  /

13 rows updated.

SQL> select * from wwm2;

TOWN                         ID
-------------------- ----------
                            222
lllldf                      111
lllldf                      111
                           1111
                           2222
lllldf                      111
lllldf                      111
lllldf                      111
lllldf                      111
                            222
lllldf                      111

TOWN                         ID
-------------------- ----------
lllldf                      111
                            222
13 rows selected.

可以看到13条记录被更新,符合条件的更新正确,不符合条件的也更新为NULL.以下是正确的方法

方法一:
SQL> update wwm2
  2  set town=(select town from wwm5 where wwm5.id=wwm2.id)
  3  where id=(select wwm5.id from wwm5 where wwm5.id=wwm2.id)
  4  /

8 rows updated.

方法二:    与方法一道理相同,这里需要掌握EXIST的相关用法.
SQL> update wwm2
   set town=(select town from wwm5 where wwm5.id=wwm2.id)
   where exists (select 1 from wwm5 where wwm5.id=wwm2.id)
8 rows updated.

方法三:
SQL> update (select a.town atown,a.id aid,b.town btown,b.id bid from wwm2 a,wwm5 b where a.id=b.id)
  2  set atown=btown
  3  /
set atown=btown
    *
ERROR at line 2:
ORA-01779: cannot modify a column which maps to a non key-preserved table

1* alter table wwm5 add primary key (id)
SQL> /

Table altered.

1  update (select a.town atown,a.id aid,b.town btown,b.id bid from wwm2 a,wwm5 b where a.id=b.id) -- 表连接之后, 更新视图的方式很好理解. 但是需要primary key.
  2*  set atown=btown
SQL> /

8 rows updated.

这种方法的局限性就是需要PRIMARY 的支持.! 需要 更新被更新表有主键, 连接栏位是不是需要呢>?

方法四: --万金油. 但是数据库顾问说效能没有使用表连接好.
  1  declare
  2  cursor cur_wwm is select town,id from wwm5; -- 驱动 表
  3  begin
  4     for my_wwm in cur_wwm loop
  5     update wwm2 set town=my_wwm.town -- 被驱动表.
  6     where id=my_wwm.id;
  7     end loop;
  8* end;
SQL> /

PL/SQL procedure successfully completed.

SQL> select * from wwm2;

TOWN                         ID
-------------------- ----------
222                         222
lllldf                      111
lllldf                      111
llll                       1111
dddd                       2222
lllldf                      111
lllldf                      111
lllldf                      111
lllldf                      111
ljjjjj                      222
lllldf                      111

TOWN                         ID
-------------------- ----------
lllldf                      111
ljjjjj                      222

这个方法是最灵活的了.

方法五:

注意,方法五只能适用于WWM5是WWM2的子集的时候. (新特性 merge Into,哎呀! 不想学.....)
  1   merge into wwm2
  2   using (select town,id from wwm5) b
  3   on (wwm2.id=b.id)
  4   when matched then update set town=b.town
  5* when not matched then insert (town,id) values (null,null)
SQL> /

9 rows merged.

SQL> select * from wwm2;

TOWN                         ID
-------------------- ----------
                                  ---注意这个地方,被插入了一个空值.因为WWM5的ID=9984在WWM2中不能匹配,根本原因是ORACLE9必须有WHEN NOT MATCHED子句,但是ORACLE10可以不许要,也就是ORACLE10可以不写WHEN NOT MATCHED ,就不必插入NULL值了,为解决这个问题,下一步会DELETE WWM5的ID=9984,这样一来就不会执行WHEN NOT MATCHED
222                         222
lllldf                      111
lllldf                      111
llll                       1111
dddd                       2222
lllldf                      111
lllldf                      111
lllldf                      111
lllldf                      111
ljjjjj                      222

TOWN                         ID
-------------------- ----------
lllldf                      111
lllldf                      111
ljjjjj                      222

14 rows selected.

SQL> delete from wwm5 where id=9984;

1 row deleted.

SQL>  1   merge into wwm2                             
SQL>   2   using (select town,id from wwm5) b
SQL>   3   on (wwm2.id=b.id)
SQL>   4   when matched then update set town=b.town
SQL>   5* when not matched then insert (town,id) values (null,null)
SQL> /

8 rows merged.

以上就是5种关连更新的例子了,希望能给开发人员解惑.

说明:如果select 子句可以返回多行记录,但返回适合where条件的记录只能是唯一的,否则将会报返回单行的select子句返回多行的错误,因为update只能跟据此处的where子句(内层where)进行相应记录的匹配更新,一次只能是一条。

来自为知笔记(Wiz)

时间: 2024-11-11 13:03:57

ORACLE 关连更新 update select的相关文章

oracle 关联更新

不多说了,我们来做实验吧. 创建如下表数据 select * from t1 ; select * from t2; 现需求:参照T2表,修改T1表,修改条件为两表的fname列内容一致. 方式1,update 常见陷阱: UPDATE T1 SET T1.FMONEY = (select T2.FMONEY from t2 where T2.FNAME = T1.FNAME) 执行后T1结果如下: 有一行原有值,被更新成空值了. 正确写法: UPDATE T1 SET T1.FMONEY =

Oracle并行更新的两种方式(merge/update内联视图)

对于Oracle的两表联合更新的场景(有A.B两表,以A.id=B.id关联,根据B表中的记录更新A表中的相应字段),一般有update内联视图和merge两种方式,下面举例介绍:   创建用例表: create table test1(id number(10),name varchar2(20)); create table test2(id number(10),name varchar2(20));   测试数据: begin insert into test1 values(1,'A'

update select

update中加入select 最常用的update语法是:UPDATE <table_name>SET <column_name1> = <value>, SET <column_name2> = <value> 如果我的更新值Value是从一条select语句拿出来,而且有很多列的话,用这种语法就很麻烦第一,要select出来放在临时变量上,有很多个哦第二,再将变量进行赋值.列多起来非常麻烦,能不能像Insert那样,把整个Select语句的

SQL update select结合语句详解及应用

来源:http://www.aimks.com/sql-update-the-select-statement-application.html QL update select语句 最常用的update语法是: UPDATE TABLE_NAME SET column_name1 = VALUE WHRER column_name2 = VALUE 如果我的更新值Value是从一条select语句拿出来,而且有很多列的话,用这种语法就很麻烦 第一,要select出来放在临时变量上,有很多个很难

Oracle 中for update和for update nowait的区别

http://www.cnblogs.com/quanweiru/archive/2012/11/09/2762223.html 1.for update 和 for update nowait 的区别: 首先一点,如果只是select 的话,Oracle是不会加任何锁的,也就是Oracle对 select 读到的数据不会有任何限制,虽然这时候有可能另外一个进程正在修改表中的数据,并且修改的结果可能影响到你目前select语句的结果,但是因为没有锁,所以select结果为当前时刻表中记录的状态.

Oracle 批量更新表字段

Oracle 批量更新表字段 CreateTime--2018年2月27日16:02:24 Author:Marydon (一) 将数字替换成汉字 第一步,去重查询 使用distinct关键字先对该字段值进行去重查询,看共有几种情况 --查询指定区间内表停诊字段的值 SELECT DISTINCT T.CLOSE_TZ FROM CONSULT_SCHEDULE T WHERE T.SCHEDULE_DATE BETWEEN TO_DATE('2018-01-01', 'yyyy-MM-dd')

Oracle中的 UPDATE FROM 解决方法

在表的更新操作中,在很多情况下需要在表达式中引用要更新的表以外的数据.象sql server提供了update的from 子句,可以将要更新的表与其它的数据源连接起来.虽然只能对一个表进行更新,但是通过将要更新的表与其它的数据源连接起来,就可以在update的表达式中引用要更新的表以外的其它数据.例如: UPDATE Table2SET Table2.ColB = Table2.ColB + Table1.ColBFROM Table2INNER JOIN Table1ON (Table2.Co

oracle菜鸟学习之 select case when的使用

[toc] oracle菜鸟学习之 select case when的使用 格式语法 case when 条件1 then action1 when 条件2 then action2 when 条件3 then action3 when 条件N then actionN else action end 例子 判断现在是几月 SQL> select case substr('20181118',5,2) 2 when '08' then '8yue' 3 when '09' then '9yue'

oracle不支持update from的语法

更新一个表中的数据,但条件需要和另外的表进行连接:sql server可以使用update from语法,可参考下面的链接: https://www.cnblogs.com/cnmarkao/p/3687398.html 昨天因更新,数据库是oracle的,发现oracle不支持update from的语法 昨晚根据需要改写了下: update tabAset (col1,col2,col3,col4,col5)=(select b.col1,b.col2,substr(b.col3,4,2),