2013-09-24 83 views
0

我有一個奇怪的業務需求,讓我難倒了。一些背景:基本上,我有兩張用於跟蹤程序增強的表格:增強和Bug。 Enhancement-> Bug的關係是1:m,Bug表有一個外鍵列EnhancementID。數據庫設計:基於另一個表的狀態

這兩個表都有一個「狀態」列,但這是棘手的地方。我的要求是增強的狀態取決於其相關的錯誤。例如,如果我們有3個增強ID爲100的錯誤和「正在測試」狀態,則增強100的狀態應該自動設置爲「正在測試」。有幾個這樣的狀態規則。

這個數據庫由幾個應用程序共享,所以我的第一個想法是在Bug表上使用「On Update」觸發器。因爲觸發器在觸發表中有Select語句,所以我收到了一個「mutating table」錯誤(當觸發器觸發時,我必須查詢具有指定EnhancementID的所有錯誤的狀態)。現在,我試圖實現一個三觸發器解決方案,如下所示:http://asktom.oracle.com/pls/asktom/ASKTOM.download_file?p_file=6551198119097816936但我越來越擔心在數據庫觸發器中放置如此​​多的邏輯。

所以我的問題是:我是否合理地接近這個問題?有人可以建議更好的方法嗎?也許使用增強狀態的視圖?

回答

5

使用視圖。

沒有簡單的方法來同步跨行/表的數據。正如您發現觸發器會導致錯誤發生變化並且是不可數的錯誤的來源。如果你想避免變異錯誤,看看這個workaround by Tom Kyte(這可能會幫助你理解觸發器在這種情況下不是最好的工具)。

你可以使用應用程序或PL/SQL API,但請注意,如果你使用他們所有的時間(這意味着你永遠不會發出一個直接更新到這些表),他們只會工作。忘記使用API​​的單個開發人員會使數據不同步。就我個人而言,如果狀態非常複雜以便即時計算視圖在性能方面不可接受,我只會考慮API。

由於這是冗餘信息(增強的狀態可以從它的錯誤的地位完全扣除),就不需要將其存儲在一個數據庫列。

如果你可以表達你的SQL查詢規則,這很簡單,例如:

CREATE OR REPLACE VIEW enhancement_with_status_v AS 
SELECT e.*, 
     CASE WHEN COUNT(DECODE(b.status, 'T', 1)) >= 1 THEN 'T' 
      WHEN ... 
      ELSE ... 
     END status 
    FROM enhancement e, 
    LEFT JOIN bugs b ON b.enhancement_id = e.enhancement_id 
GROUP BY e... 

如果規則太複雜,你可以寫一個PL/SQL函數從SQL調用這個函數。

該視圖還具有當規則更改(如大多數規則那樣)時的優點,您不需要更新整個表。

+0

我實際上是根據Tom Kyte提供的解決方案中的建議來構建觸發器。另一個問題是,我無法真正改變應用程序以使用當前增強表中的不同表格。根據這個視圖是否可以更新增強表的狀態? – user2811300

+0

所以你正試圖解決帶有觸發器的應用程序,那一定是......不愉快!你可以重新命名你的表格並調用視圖「增強」,但這可能會引發更多的問題。實際上,如果您無法控制應用程序,意想不到的後果將很難預測。 –

+0

同意@VincentMalgrat - 如果可以,請使用視圖。除非你有某種形式的鎖定(建議的基於觸發器的解決方法沒有),基於觸發器的方法無法正常工作 - 基本問題是觸發器無法「看見」其他事務所做的更改(如添加或更新狀態爲「正在測試」的另一個錯誤)。 –

0

this類似的東西可能有效。

嘗試在更新後觸發一次,以檢查每個增強的不同狀態並更新增強中的相同狀態。

+0

我認爲這與我在第一次嘗試時所嘗試的類似,其中我在觸發器中使用SELECT時收到「變異表」錯誤。 – user2811300

+0

如果您嘗試在更新表a後更新表b,爲什麼要面對變異表錯誤? – SriniV

+0

因爲我必須查詢觸發器中的表a以確定表b上的狀態更新。這會導致突變表錯誤。 – user2811300

0

我看到了兩個解決方案。

  1. 數據庫觸發器中的問題
  2. 使用應用程序的手動更新父狀態(增強的狀態)提及。不要忘記在子表中索引外鍵,否則在分佈式應用系統中死鎖是不可避免的。
+0

謝謝,但使用應用程序並不是真正的選擇:數據庫在少數應用程序之間共享。 – user2811300