2008-10-23 65 views
13

我需要編寫一個更新語句,該語句使用多個表來確定要更新哪些行,因爲在Oracle中不允許有多個表。下面的查詢將返回一個「ORA-00971:缺少SET關鍵字」錯誤在Oracle更新語句中使用子查詢而不是表名

UPDATE 
    TABLE1 a, 
    TABLE2 b 
SET 
    a.COL1 = 'VALUE' 
WHERE 
    a.FK = b.PK 
    AND b.COL2 IN ('SET OF VALUES') 

仰望甲骨文UPDATE語句的語法,我發現下面的link,這表明你可以在地方的使用子查詢表名。

當我試圖寫這樣的查詢,我得到了一個「ORA-01779:不能修改它映射到非鍵保存表列」

UPDATE 
    (
    SELECT 
     a.COL1 
    FROM 
     TABLE1 a, 
     TABLE2 b 
    WHERE 
     a.FK = b.PK 
     AND b.COL2 IN ('SET OF VALUES') 
) update_tbl 
SET 
    update_tbl.COL1 = 'VALUE' 

我重寫查詢(秀下面)使用EXISTS語句來代替,它工作正常,但仍然想知道這是如何完成的。

UPDATE 
    TABLE1 update_tbl 
SET 
    update_tbl.COL1 = 'VALUE' 
WHERE 
    EXISTS (
    SELECT 
     1 
    FROM 
     TABLE1 a 
     TABLE2 b 
    WHERE 
     a.FK = b.PK 
     AND b.COL2 IN ('SET OF VALUES') 
     AND update_tbl.PK = a.PK 
) 

謝謝! -Net

回答

7

另一種選擇:如果(a)的觀點包括TABLE1的宣佈 PK

UPDATE TABLE1 a 
SET a.COL1 = 'VALUE' 
WHERE a.FK IN 
(SELECT b.PK FROM TABLE2 b 
    WHERE b.COL2 IN ('SET OF VALUES') 
) 

你的第二個例子將工作:

UPDATE 
    (
    SELECT 
     a.COL1, a.PKCOL 
    FROM 
     TABLE1 a, 
     TABLE2 b 
    WHERE 
     a.FK = b.PK 
     AND b.COL2 IN ('SET OF VALUES') 
) update_tbl 
SET 
    update_tbl.COL1 = 'VALUE' 

...和(b)TABLE1。 FK是宣稱外鍵到TABLE2

(通過聲明我的意思是一個約束存在,是ENA流血)。

0

UPDATE子句中查詢的結果集中的每一行都必須映射回表中您想要更新的表中的一行,並且只有一行可以自動跟蹤。由於查詢確實是一個視圖,因此需要考慮的一個方法是Oracle需要能夠將視圖加入到目標表中,以便知道要更新的行。

這基本上意味着您需要在該查詢中包含目標表的主鍵。您可能也可以使用其他一些獨特的索引字段,但我不能保證Oracle DBMS足夠聰明以允許這樣做。

2

當您執行更新時,顯然只能告訴系統將該值更新爲單個新值 - 告訴它將「X」更新爲「Y」和「Z」沒有意義。因此,當您對內聯視圖的結果進行更新時,Oracle會執行檢查,確保有足夠的約束來防止修改的列可能更新兩次。

在你的情況,我期望TABLE2.PK實際上不是一個聲明的主鍵。如果你在這個柱子上放置一個主要的或者唯一的約束條件,那麼你可以很好地去。

通過Oracle內部使用的更新連接基數檢查有一個無證的提示,但我不建議使用它。

對此的一個解決方法是使用MERGE語句,該語句不受相同的測試。

3

您的示例的語法很好,但Oracle要求子查詢包含主鍵。這是一個非常重要的限制。

在一個相關的說明,您還可以使用括號來使用2個或多個字段中的報表,如:

UPDATE 
    TABLE1 update_tbl 
SET 
    update_tbl.COL1 = 'VALUE' 
WHERE 
    (update_tbl.PK1, update_tbl.pk2) in(
         select some_field1, some_field2 
         from some_table st 
         where st.some_fields = 'some conditions' 
        ); 
6

我發現一個好的,快速,一致的方式把一個SELECT語句進入UPDATE是基於ROWID進行更新。

UPDATE 
    TABLE1 
SET 
    COL1 = 'VALUE' 
WHERE 
    ROWID in 
    (
    SELECT 
     a.rowid 
    FROM 
     TABLE1 a, 
     TABLE2 b 
    WHERE 
     a.FK = b.PK 
     AND b.COL2 IN ('SET OF VALUES') 
    ) 

因此,您的內部查詢正在定義要更新的行。

1

我發現我需要的東西在這裏: Useful SQL Commands

,我需要的結果更新一個表連接
我嘗試沒有成功:(

在這裏,上述解決方案是提取物我指出的頁面
使用光標我能夠成功實現任務
我敢肯定還有另一種解決方案,但這個工作,所以...

DECLARE 

/* Output variables to hold the result of the query: */ 
a T1.e%TYPE; 
b T2.f%TYPE; 
c T2.g%TYPE; 

/* Cursor declaration: */ 
CURSOR T1Cursor IS 
    SELECT T1.e, T2.f, T2.g 
    FROM T1, T2 
    WHERE T1.id = T2.id AND T1.e <> T2.f 

FOR UPDATE; 

BEGIN 

    OPEN T1Cursor; 

    LOOP 

    /* Retrieve each row of the result of the above query 
    into PL/SQL variables: */ 
    FETCH T1Cursor INTO a, b; 

    /* If there are no more rows to fetch, exit the loop: */ 
    EXIT WHEN T1Cursor%NOTFOUND; 

    /* Delete the current tuple: */ 
    DELETE FROM T1 WHERE CURRENT OF T1Cursor; 

    /* Insert the reverse tuple: */ 
    INSERT INTO T1 VALUES(b, a); 

    /* Here is my stuff using the variables to update my table */ 
    UPDATE T2 
    SET T2.f = a 
    WHERE T2.id = c; 

    END LOOP; 

    /* Free cursor used by the query. */ 
    CLOSE T1Cursor; 

END; 
. 
run; 


注:請不要忘記提交;-)

相關問題