2009/07/10

Oracle SQL使用兩個Table進行Update的方法

Oracle SQL和MS-SQL寫法不太一樣,上網搜尋了兩天,都是同一篇文章(好笑的是我看了十幾篇還是不清楚作者是誰),腦袋不是很清醒的我,睡了一覺才搞清楚到底要怎麼寫,要寫這種語法大概一年不到一次,所以還是先記錄下來為妙。

  原文參考: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還要快的關係,所以第一種寫法只適用於小量資料。



8 則留言:

  1. 不好意思,想請教一下,關於View的建立。您所說的 "使用View來建立" 的那段SQL並無Create View 的語法 (如 Create View XXX AS (Select ......)),想請問建立View是否有不同於上式的寫法?

    回覆刪除
  2. 是的,這裡說得View僅僅是指資料篩選集合,不是實體的View表單

    回覆刪除
  3. 請問若是update 變數,例如:A2=B3,則上述SQL對嗎?

    回覆刪除
  4. 不好意思,請問「則上述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的寫法會較快

    回覆刪除
  5. 我將Cursor寫法補充上了,有興趣可以參考此篇:http://hironokai.blogspot.com/2011/11/oraclecursor.html

    回覆刪除
  6. 請問用SQL的寫法 我需要將B表的值全部取代A表,當B表欄1=A表欄1時,也可以用View嗎? 我的資料有3萬多筆。

    回覆刪除
  7. 多謝版主的隨手紀錄
    對於多年過後的我根本是神救援!!!

    回覆刪除