Oracle
Oracle:非鍵保留表應該是
當我嘗試更新連接時,我收到“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 中生成上述錯誤。
所以兩個問題:
- 你能看出我的查詢有什麼問題嗎?2)您能否建議我的開發環境和生產環境(例如伺服器設置)之間可能會導致此錯誤但不會導致另一個錯誤的不同之處?
如果滿足以下條件,您可以更新 Oracle中的聯接:
- 只更新一張基表
- 所有其他表都是鍵保留的:對於基表的每一行,它們中的每一個都必須最多有一行。
(適用於更新視圖的其他限制)
在您的範例中,您
PG_MACHINE
僅更新表。Oracle 必須確保對於該表的單行,只能找到另一行。這似乎是這種情況,因為你有一個 PKPG_LABLOCATION.LABLOCID
。因此,您應該能夠更新聯接。例如,請參閱具有類似設置的 SQLFiddle。在您的情況下,您應該:
- 確保主鍵已啟用、驗證、不可延遲(有趣的是,可延遲約束會阻止 Oracle 更新連接!)
- 使用
MERGE
ifPG_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 中的父級。