Oracle

Oracle:非鍵保留表應該是

  • June 21, 2019

當我嘗試更新連接時,我收到“ORA-01779:無法修改映射到非鍵保留表的列”。我在該站點上進行了搜尋,發現了很多關於保留密鑰的含義以及為什麼需要保留的建議……但據我所知,我正在遵守該建議,但仍然遇到錯誤。

我有兩張桌子:

PG_LABLOCATION has, among other things, the columns:
"LABLOCID" NUMBER,
"DNSNAME" VARCHAR2(200 BYTE)

LABLOCID is the primary key, DNSNAME has a unique constraint

PG_MACHINE has, among other things, the columns:
"MACHINEID" NUMBER, 
"LABLOCID" NUMBER, 
"IN_USE" NUMBER(1,0) DEFAULT 0, 
"UPDATE_TIME" TIMESTAMP (6) DEFAULT '01-JAN-1970'

MACHINEID is a primary key
LABLOCID is a foreign key into LABLOCID in PG_LABLOCATION (its primary key)

我正在執行的更新是:

update 
 (select mac.in_use, mac.update_time
    from pg_machine mac 
    inner join pg_lablocation loc
      on mac.lablocid = loc.lablocid
    where loc.dnsname = 'value'
      and '02-JAN-2013' > mac.update_time
 )
set in_use = 1 - MOD( 101, 2 ), update_time = '02-JAN-2013';

我只更新一個表(PG_MACHINE)中的值,而另一個表中的連接列是主鍵,這應該使它在我的閱讀中保留鍵。我擔心 where 子句會導致問題,但我嘗試刪除 mac.update_time 上的過濾器並得到相同的錯誤,並且 loc.dnsname 具有唯一約束。

更奇怪的是,像許多人一樣,我們擁有開發和生產環境。我們完成了從 prod 到 dev 的完整架構和數據遷移。我已經查看了它們,它們具有相同的索引和約束。該查詢在 dev 中有效,但在 prod 中生成上述錯誤。

所以兩個問題:

  1. 你能看出我的查詢有什麼問題嗎?2)您能否建議我的開發環境和生產環境(例如伺服器設置)之間可能會導致此錯誤但不會導致另一個錯誤的不同之處?

如果滿足以下條件,您可以更新 Oracle中的聯接:

  1. 只更新一張基表
  2. 所有其他表都是鍵保留的:對於基表的每一行,它們中的每一個都必須最多有一行。

(適用於更新視圖的其他限制

在您的範例中,您PG_MACHINE僅更新表。Oracle 必須確保對於該表的單行,只能找到另一行。這似乎是這種情況,因為你有一個 PK PG_LABLOCATION.LABLOCID。因此,您應該能夠更新聯接。例如,請參閱具有類似設置的 SQLFiddle

在您的情況下,您應該:

  • 確保主鍵已啟用、驗證、不可延遲(有趣的是,可延遲約束會阻止 Oracle 更新連接!)
  • 使用MERGEifPG_LABLOCATION.LABLOCID對於相關查詢是唯一的。MERGE不如使用連接更新嚴格,並且僅在結果集中實際上UPDATE存在重複時才會返回錯誤(而如果存在重複的可能性則會失敗)。
  • 查看您的查詢,因為您不需要SELECT子句中父表中的值,您可以將其重寫為半連接(保證不會生成重複):
UPDATE (SELECT mac.in_use, mac.update_time
         FROM pg_machine mac
        WHERE mac.lablocid IN (SELECT loc.lablocid 
                                 FROM pg_lablocation loc 
                                WHERE loc.dnsname = 'value')
          AND to_date('02-JAN-2013') > mac.update_time)
  SET in_use = 1 - MOD(101, 2), 
      update_time = to_date('02-JAN-2013');

這可以重寫為:

UPDATE pg_machine mac
  SET in_use = 1 - MOD(101, 2), 
      update_time = to_date('02-JAN-2013')
WHERE mac.lablocid IN (SELECT loc.lablocid 
                         FROM pg_lablocation loc 
                        WHERE loc.dnsname = 'value')
  AND to_date('02-JAN-2013') > mac.update_time;

在這種情況下,我會選擇第三個選項:通常你不能更新 parent-child join 中的父級

引用自:https://dba.stackexchange.com/questions/38728