2012-11-27 19 views
0

當試圖向表格中插入數據時,它可能會由於各種原因而失敗,如違反唯一鍵或違反外鍵。Oracle - 我應該使用異常還是觸發器?

我可以使用DUP_VAL_ON_INDEX異常知道唯一鍵被違反,但我怎麼知道哪個鍵是否有多列具有唯一標記?我應該在這種情況下使用觸發器嗎?

(我使用的例外驅動的存儲過程而不是查詢表的流動,使插入確保數據是好的。)

回答

0

例外(從約束)或觸發器?我說也不是。

我會強烈推薦使用應用程序代碼和查詢來驅動應用程序的邏輯,而不是觸發器和約束。將邏輯從錯誤條件處理中分離出來只會讓代碼的行爲顯得更神奇。

儘管約束作爲備份計劃(在應用程序邏輯錯誤或更改的情況下)是非常有用的,但您是正確的,因爲它們不以您希望的方式幫助處理運行時錯誤處理(即,不幫助您公開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.

但是,這仍然不會讓您違反密鑰值。您將不得不編寫查詢來確定哪些內容會違反約束條件。

+0

你插入語句仍然不會告訴你哪個列重複試圖發生,對吧? – user1831003

+0

不,這是真的。你將不得不查詢回來。 – Ben

0

這不是觸發器的用途。請記住,你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; 
+0

感謝您指出觸發器是出了問題。但是,我需要知道這一點:如果我用上面的代碼,我怎麼會知道哪些獨特的列中的異常發生呢? – user1831003

+0

我不認爲有任何方法可以自動說出。您可能必須執行「SELECT」來查找現有的匹配鍵。我想說在大多數情況下,這並不重要。 – eaolson

0

對於它的價值,我建議你做單靠在應用程序代碼上執行唯一性。一個關鍵的(雙關語意)的原因是,這是很難編寫代碼,正確地做到這一點,特別是在數據被插入或多個事務併發更新的情況。聲明數據庫將正確有效地執行的唯一約束相對簡單。

如果你想知道哪些違反唯一約束,一種方法(我意識到這不是「漂亮」)是:

  1. 解析錯誤消息中的約束名(例如,由SQLERRM返回)。
  2. 使用某種機制(如數據字典或您自己的表),以「查找」,這列對應於約束。

如果你想知道哪些違反唯一約束行,你可以使用INSERT語句的LOG ERRORS INTO子句違規行登錄到一個錯誤記錄表,如this example概述。

如果你想知道哪些行列違反唯一約束,你可以結合這兩種方法 - 您登錄使用LOG ERRORS INTO子句中的行,然後解析從錯誤消息constaint名(也記錄在錯誤記錄表中)並查找相應的列。

話雖如此,您不一定需要在以下幾種情況中進行選擇:a)首先檢查數據,如果通過檢查,則只插入數據; b)嘗試插入數據,然後報告和/或採取行動任何錯誤。

相關問題