原文參考:Oracle中的UPDATE FROM解决方法
MS-SQL(SQL Server)提供Update語法可使用From,例:
Update A Set A.A2 = '1' From A,B Where A.A1=B.B1 And B.B2 = '2' |
當要更新A表的A2欄位時,要經過篩選條件,而篩選條件由B表的B2欄位決定時需要經過兩個表的聯集,可以直接改寫成Select條件取得篩選結果。
Select A.* From A,B Where A.A1=B.B1 And B.B2 = '2' |
不過Update From這種寫法在Access和Oracle裡都不適用,在Access裡下這樣的SQL會在From部份顯示錯誤,在Oracle裡則是出現ORA錯誤。
所以不使用From來下Update指令,先用Select條件取得篩選結果:
Select A.* From A Where A.A1 in (Select B.B1 From B Where B.B2='2') |
取得結果會一樣,所以再代回去Update SQL:
Update A Set A.A2 = '1' Where A.A1 in (Select B.B1 From B Where B.B2='2') |
這個方法在Access和Oracle都適用,但是在實際測試後發現有個很大的問題,那就是我的Oracle資料裡,A表有上十萬筆資料,B表更有上百萬筆,當A表的指標向下移動一筆時,B表就要重頭跑一次到最後一筆,如果篩選條件越複雜,那麼花費時間就會更久,所以這種寫法的花費時間是[A表筆數 x B表筆數],這種時間去做Update首先使用者一定會以為電腦當機了,再來就是主機真的會當掉,同一時間並不是只有一個使用者,當執行被鎖定在這個Update裡時其他人就無法執行其他更改動作,不能執行的時間越長,就會發生越多問題。
因此資料量大的時候,改採用網路上說的另一種寫法,也就是利用View來做:
Update ( Select A.A2 From A Where A.A1 in (Select B.B1 From A,B Where A.A1=B.B1 And B.B2='2')) Set A2 = '1' |
因為Update必須僅為單一個Table(Update View的限制),所以必須多一層來宣告是哪個Table要進行 Update,如果寫成以下寫法,則會造成ORA錯誤(不可更新的View):
Update ( Select A.A2 From A,B Where A.A1=B.B1 And B.B2='2') Set A2 = '1' |
兩種寫法都可成立,但資料量極大時在速度和效能上有明顯差異,或許是執行速度上Join比In還要快的關係,所以第一種寫法只適用於小量資料。
不好意思,想請教一下,關於View的建立。您所說的 "使用View來建立" 的那段SQL並無Create View 的語法 (如 Create View XXX AS (Select ......)),想請問建立View是否有不同於上式的寫法?
回覆刪除是的,這裡說得View僅僅是指資料篩選集合,不是實體的View表單
回覆刪除請問若是update 變數,例如:A2=B3,則上述SQL對嗎?
回覆刪除不好意思,請問「則上述SQL對嗎?」的上述SQL是?
回覆刪除如果你的意思是要將B表中的欄位值寫入A表中
則SET部份要另外加入SQL
無法直接取用Update裡的B表值
所以大約寫法會是這樣(注意Set下的SQL必須傳回單一值):
Update ( Select A.A2
From A
Where A.A1 in (Select B.B1
From A,B
Where A.A1=B.B1
And B.B2='2'))
Set (A2, A3) = (Select B.B3, B.B4
From A,B
Where A.A1=B.B1
And B.B2='2')
P.s. Oracle除非必要,否則建議資料量大時使用cursor的寫法會較快
我將Cursor寫法補充上了,有興趣可以參考此篇:http://hironokai.blogspot.com/2011/11/oraclecursor.html
回覆刪除請問用SQL的寫法 我需要將B表的值全部取代A表,當B表欄1=A表欄1時,也可以用View嗎? 我的資料有3萬多筆。
回覆刪除可以的喔
回覆刪除多謝版主的隨手紀錄
回覆刪除對於多年過後的我根本是神救援!!!