2014-03-12 58 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行。 –