准備階段
1.建表語句:
create table table1(
idd varchar2(10) ,
val varchar2(20)
);
create table table2(
idd varchar2(10),
val varchar2(20)
);
2.插入數據:
insert into table1 values ('01','1111');
insert into table1 values ('02','222');
insert into table1 values ('02','2222');
insert into table1 values ('03','3333');
insert into table1 values ('04','4444');
insert into table1 values ('06','6666');
commit;
insert into table2 values ('01','aaaa');
insert into table2 values ('02','bbbb');
insert into table2 values ('03','cccc');
insert into table2 values ('04','dddd');
insert into table2 values ('05','eee');
commit;
3.兩張表如下圖:
要將 table2中idd - val 的值,賦值給table1對應的 idd - val;
為了驗證操作的合理性,設置了如下幾個需要額外考慮情況:
注意兩表特殊地方在於:
- table1中,有1條
idd
字段值為06
的數據,table2中idd
字段沒有06
,命名為e1
; - table1中,有2條
idd
字段值都為02
,並且對應的val
不同的數據,命名為e2
,以下都能正常解決此情況; - table2中,有2條
idd
字段值都為05
,但對應的val
值不同的數據,命名為e3
,待添加;
sql查詢:
1. 最容易想到的辦法:通過子查詢 ,直接 update
,如下:
update table1 set table1.val = (select val from table2 where table1.idd = table2.idd);
- 問題:我們遇到了
e1
情況,即table1中06
對應的值被改變了-->val變成了null(即圖中的空白);
這並不是我們的本意,故做出如下改進。
2. 加入限制條件,對於 table1中有值,但是table2中無值的idd
字段,不做修改;
update table1 set val = (select val from table2 where table1.idd = table2.idd)
where exists (select 1 from table2 where table1.idd = table2.idd)
- 第2種寫法看似沒問題,但如果我們再次向table2中插入一條數據,
insert into table2 values ('03','ccc');
遇到了e3
情況, - 執行后會報錯如下:
ORA-01427:單行子查詢返回多個行
3. 通過上述分析,簡單的更新語句並不能解決遇到的異常情況。所以我們可以使用merge
,如下:
merge into table1
using table2
on (table1.idd = table2.idd)
when matched then
update set table1.val = table2.val
- 雖然可以解決
e1
情況,然而遇到e3
情況時,仍然報錯,如下:
ORA-30926: 無法在源表中獲得一組穩定的行
4. 最后,在3的基礎上,加入限制條件,即可解決;
merge into table1
using (select t.idd ,max(t.val) m from table2 t group by t.idd)table2
on (table1.idd = table2.idd)
when matched then
update set table1.val = table2.m
- 上述寫法在
using
后面構造了一個新的table2,但一定要對val做出處理,如果是varchar類型,可以選擇 max,min等函數,如果number類型,可以使用sum,avg等函數,總之,要對val做出處理(對應多個的時候,到底要哪個?最大的還是最小的),新的table2是一個idd對應一個val。 - 為什么構造新的table2時要加
group by t.idd
,因為select max(t.val) m from table2 t
查詢的是一條數據,t.idd
不屬於這條數據的任何字段,故select t.idd
后報錯,拼接group by t.idd
便可以查出需要的idd字段。(針對oracle數據庫,mysql並不會)
參考:Oracle中用一個表的數據更新另一個表的數據
Group by 中avg();sum();min();max();count();的運用整理(Oracle的執行順序)