2014-03-12 50 views
4

我正在使用Hibernate 4和Oracle 11g在Web應用程序上工作。如何在多個表中創建條件唯一約束?

我在這種情況下正在使用以下表格。爲了保護無辜者,表格已被更改和簡化。

entry 
ID | name | 
1 | thing1 | 
2 | thing2 | 

entry_number 
ID | value | entry_id| type_id | 
1 | 11111 | 1  | 1  | 
2 | 22222 | 1  | 2  | 
3 | 33333 | 1  | 2  | 
4 | aaaaa | 2  | 1  | 
5 | bbbbb | 2  | 2  | 
6 | ccccc | 2  | 2  | 

type 
ID | name | 
1 | unique | 
2 | regular | 
3 | etc. | 
... 

的想法是,我希望有條件地限制入口號的插入,這樣只能有型「獨特的」分配給任何給定條目的一個數字。不幸的是,許多簡單的約束方法不適用於這種情況。經過一番研究,我發現以下解決方案工作:

create unique index unique_entry_number on entry_number(CASE WHEN TYPE_ID = 1 THEN entry_id ELSE null END); 

我不喜歡這個唯一的一點是,我引用id爲「TYPE_ID」,我不相信我可以必然依賴於一致。而且Oracle不會讓我在唯一索引內部使用子查詢來加入「type.name」,我可以依靠它來保持一致。

有沒有不同的方法,我應該使用,我不知道或有任何建議,我可以緩解這個問題?最好在代碼更改或數據模型更改方面儘可能不干擾?或者這只是我必須學會處理的一個現實?

+0

您討論的是什麼'item_number'?我沒有在你的數據模型中看到它。 –

+0

您想要實現的「獨特性」聽起來像是不適合在關係數據庫中作爲約束條件的東西,但是就像應該在您的代碼/ UI中強制實施的東西。 –

+0

@KlausByskovPedersen對不起,我通過我的帖子對派對方式進行了一些更改,並忘記在某些地方進行更改。我編輯它是一致的。 –

回答

1

事實證明,你可以在物化視圖上有一個檢查約束;所以,你應該能夠編寫這樣的事:

CREATE MATERIALIZED VIEW LOG 
    ON entry_number 
    WITH ROWID 
; 
CREATE MATERIALIZED VIEW LOG 
    ON type 
    WITH ROWID 
; 
CREATE MATERIALIZED VIEW entry_number_counter 
    REFRESH FAST 
    ON COMMIT 
    AS SELECT en.entry_id, COUNT(1) AS row_count 
      FROM entry_number en 
      JOIN type ON entry_number.type_id = type.id 
      WHERE type.name = 'unique' 
      GROUP BY en.entry_id, type.name 
; 
ALTER TABLE entry_number_counter 
    ADD CONSTRAINT entry_id_conditionally_unique 
     CHECK (row_count = 1) 
; 

(免責聲明:沒有測試過這是改編自Tom Kyte's "The Trouble With Triggers"一個例子,如果你決定走這條路,你會希望通過閱讀。首先是文檔並理解它;特別是,我不太清楚「物化視圖日誌」部分,並且可能需要進行一些調整。)

+0

我不得不做出一些改變才能使其發揮作用,但這看起來很有希望。但值得關注的是空間和性能。從我讀過的內容來看,日誌在很大程度上取決於性能(如緩存)來啓用「快速刷新」,因此無需一次刷新大量數據。我的閱讀似乎也表明,對於大量數據來說它是很好的,但是當我查看具有小樣本集的物化視圖表時,幾乎與入口表一樣多。這很令人擔憂,因爲現實世界的「入口」表非常大。我應該擔心嗎? –

+0

@Blue_Helix:我已經編輯了使物化視圖更小的答案。但即便如此 - 是的,這是一個嚴重的折衷。因爲聽起來你的'type'表或多或少是固定的,所以按照你最初的計劃添加一個正常的函數索引可能會更容易,並且只是接受這樣一個事實,即在填充'type'後你的索引必須被創建。 – ruakh

+0

@Blue_Helix您可以在MATERIALIZED VIEW定義中添加一個條件,以濾除不需要的項目:'HAVING count(1)!= 1'這樣物化視圖將有0行。 –