2010-04-20 49 views
1

为了说明问题,我让一个例子:唯一约束(W/O触发)上的“一到多”关系

甲tag_bundle由一个或一个以上的标记。 独特的标签组合可以映射到唯一的标签块,反之亦然。

tag_bundle     tag   tag_bundle_relation 
+---------------+  +--------+  +---------------+--------+ 
| tag_bundle_id |  | tag_id |  | tag_bundle_id | tag_id | 
+---------------+  +--------+  +---------------+--------+ 
|  1  |  | 100 |  |  1  | 100 | 
+---------------+  +--------+  +---------------+--------+ 
|  2  |  | 101 |  |  1  | 101 | 
+---------------+  +--------+  +---------------+--------+ 
          | 102 |  |  2  | 101 | 
          +--------+  +---------------+--------+ 
              |  2  | 102 | 
              +---------------+--------+ 

不能有具有正好从标签100和标签相同的组合101 不能有具有正好从标签101和标签102

同一组合的另一tag_bundle另一个tag_bundle如何确保执行SQL “同时”时的这种唯一约束! 就是防止同时将两束具有完全相同相同标签组合

添加任何表不起作用简单的唯一约束, 难道还有比触发或显式锁以外的任何解决方案。

我只想到了这样一种简单的方法:将标记组合变成字符串,并让它成为一个独特的列。

tag_bundle (unique on tags)   tag   tag_bundle_relation 
+---------------+-----------+  +--------+  +---------------+--------+ 
| tag_bundle_id | tags  |  | tag_id |  | tag_bundle_id | tag_id | 
+---------------+-----------+  +--------+  +---------------+--------+ 
|  1  | "100,101" |  | 101 |  |  1  | 101 | 
+---------------+-----------+  +--------+  +---------------+--------+ 
            | 100 |  |  1  | 100 | 
            +--------+  +---------------+--------+ 

但它似乎不是一个好办法:(

+0

您是否希望允许tab_id参与多个捆绑包?例如,'tag_bundle_id = 2'有'tags =(100,200)'?超级集合/子集怎么样,'tag_bundle_id = 3是否有标签(100,101,102)'? – 2010-04-20 21:44:19

+0

tag_bundle_id = 2允许标签=(100,200), tag_bundle_id = 3允许标签(100,101,102)。 – elgcom 2010-04-20 21:53:31

+0

那么,是或否的子集? – MkV 2010-04-20 23:52:49

回答

1

为什么的“没有触发器”约束?有了它,带着几分重复数据的结合,你可以得到你所需要的。更改解决方案中的'标签'字段到INTEGER的数组字段(或任何类型的tag_id)

虽然认识到解决方案的不愉快性,但我没有看到它的方法,尽管我会使用数组而不是'tags'的字符串,将其放在与tag_bundle分开的表中,仍然使其唯一并在tag_bundle_relation上放置一个触发器,以使用array_agg(t ag_id)(> 8.4),如果失败,触发器更新失败。

-1

为了在多个事务更新表格时正常工作,您需要创建一个可拒绝的,最初推迟的constraint trigger

+1

纠正我,如果我错了,但 - 除非您序列化函数调用 - 触发器不会保存您的竞争条件,因为并行执行的其他事务所做的更改不可见。 *延迟*约束触发器*减少了竞争条件的机会窗口,但仍有可能两个此类触发器并行运行,而不会看到彼此的(尚未完成的)数据。 – intgr 2010-04-21 14:23:52

+0

@intgr优秀的问题。我不知道答案。我推测提交事务是序列化的,因此触发器函数的处理也是推迟到事务提交时进行的。或许需要序列化隔离级别来保证这一点。如果决定是否允许更新取决于其他并发事务是提交还是回滚,那么需要首先完成其他提交或回滚以及其延迟触发器。 – 2010-04-21 22:44:50