當試圖向表格中插入數據時,它可能會由於各種原因而失敗,如違反唯一鍵或違反外鍵。Oracle - 我應該使用異常還是觸發器?
我可以使用DUP_VAL_ON_INDEX異常知道唯一鍵被違反,但我怎麼知道哪個鍵是否有多列具有唯一標記?我應該在這種情況下使用觸發器嗎?
(我使用的例外驅動的存儲過程而不是查詢表的流動,使插入確保數據是好的。)
當試圖向表格中插入數據時,它可能會由於各種原因而失敗,如違反唯一鍵或違反外鍵。Oracle - 我應該使用異常還是觸發器?
我可以使用DUP_VAL_ON_INDEX異常知道唯一鍵被違反,但我怎麼知道哪個鍵是否有多列具有唯一標記?我應該在這種情況下使用觸發器嗎?
(我使用的例外驅動的存儲過程而不是查詢表的流動,使插入確保數據是好的。)
例外(從約束)或觸發器?我說也不是。
我會強烈推薦使用應用程序代碼和查詢來驅動應用程序的邏輯,而不是觸發器和約束。將邏輯從錯誤條件處理中分離出來只會讓代碼的行爲顯得更神奇。
儘管約束作爲備份計劃(在應用程序邏輯錯誤或更改的情況下)是非常有用的,但您是正確的,因爲它們不以您希望的方式幫助處理運行時錯誤處理(即,不幫助您公開INSERT
聲明嘗試使用的重複密鑰)。
毫無疑問,您可以非常輕鬆地使用觸發器來完成您所描述的內容,但最終意味着您只是隱藏了相同的邏輯測試(「此記錄是否已存在?」)在觸發器中,而不是在存在INSERT
語句的應用程序代碼中。如果桌面上存在多個觸發器,那麼或也會經歷不必要的執行開銷,就好像人們會提出錯誤一樣,其他任何先運行的人都沒有結果。
如果你不想寫額外的語句前檢查運行新INSERT
語句之前數據的狀態,那麼我會建議使用這樣的事情:
INSERT INTO my_table (col1, col2)
SELECT l_val1, l_val2
FROM dual
WHERE NOT EXISTS (
SELECT 1
FROM my_table t
WHERE t.col1 = l_val1
AND t.col2 = l_val2
)
至少,那麼你將不會違反密鑰,但是通過測試SQL%ROWCOUNT
是否爲0(沒有行插入,因此必須已經存在)或者是否已經存在,您將知道是否已經存在一行或者1.
但是,這仍然不會讓您違反密鑰值。您將不得不編寫查詢來確定哪些內容會違反約束條件。
這不是觸發器的用途。請記住,你can not query the target table inside a trigger,所以你不能真正檢查違反唯一性。我會說觸發器的最佳理由是確保行使用默認數據填充,如序列中的ID。觸發器也會混淆代碼,因爲不清楚爲什麼插入的行與您的語句不同。
約束執行一個有用的函數,而不是顯而易見的:優化器可以使用約束中的信息來判斷執行計劃。例如,如果優化程序知道列是否爲NOT NULL,則可以計算更有效的路線。上述
通過@Ben給出的INSERT
語句是一個很好的,你也可以換一個匿名塊中的語句:
BEGIN
... application code ...
BEGIN
INSERT INTO mytable (col1, col2) VALUES (val1, val2);
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
... error handling code ...
END;
... application continues...
END;
感謝您指出觸發器是出了問題。但是,我需要知道這一點:如果我用上面的代碼,我怎麼會知道哪些獨特的列中的異常發生呢? – user1831003
我不認爲有任何方法可以自動說出。您可能必須執行「SELECT」來查找現有的匹配鍵。我想說在大多數情況下,這並不重要。 – eaolson
對於它的價值,我建議你做不單靠在應用程序代碼上執行唯一性。一個關鍵的(雙關語意)的原因是,這是很難編寫代碼,正確地做到這一點,特別是在數據被插入或多個事務併發更新的情況。聲明數據庫將正確有效地執行的唯一約束相對簡單。
如果你想知道哪些列違反唯一約束,一種方法(我意識到這不是「漂亮」)是:
SQLERRM
返回)。如果你想知道哪些違反唯一約束行,你可以使用INSERT
語句的LOG ERRORS INTO
子句違規行登錄到一個錯誤記錄表,如this example概述。
如果你想知道哪些行和列違反唯一約束,你可以結合這兩種方法 - 您登錄使用LOG ERRORS INTO
子句中的行,然後解析從錯誤消息constaint名(也記錄在錯誤記錄表中)並查找相應的列。
話雖如此,您不一定需要在以下幾種情況中進行選擇:a)首先檢查數據,如果通過檢查,則只插入數據; b)嘗試插入數據,然後報告和/或採取行動任何錯誤。
你插入語句仍然不會告訴你哪個列重複試圖發生,對吧? – user1831003
不,這是真的。你將不得不查詢回來。 – Ben