2016-12-17 138 views
2

我想在PostgreSQL中设计包含两个表彼此交叉引用的模式。但是,如果不添加冗余UNIQUE约束(请参阅下面的代码)我收到错误:ERROR: there is no unique constraint matching given keys for referenced table "nodes"为什么需要这个UNIQUE约束?

所以我的问题是:为什么这个额外的唯一约束是必要的,有没有办法避免它的创建? (以减少运行时间开销)。

CREATE TABLE objects (
    object_id serial NOT NULL PRIMARY KEY, 
    root_node integer 
); 

CREATE TABLE nodes (
    node_id integer NOT NULL PRIMARY KEY, 
    object_id integer REFERENCES objects 
); 

ALTER TABLE objects 
    ADD CONSTRAINT root_node_fkey 
    FOREIGN KEY (root_node) REFERENCES nodes(node_id); 

-- Why this constaint is needed? Since node_id is primary key this combination should be already UNIQUE 
ALTER TABLE nodes ADD CONSTRAINT node_id_object_id_unique UNIQUE (node_id, object_id); 

ALTER TABLE objects 
    ADD CONSTRAINT objects_nodes_fkey 
    FOREIGN KEY (object_id, root_node) 
    REFERENCES nodes (object_id, node_id); 

回答

2

https://www.postgresql.org/docs/current/static/ddl-constraints.html说:

5.3.5. Foreign Keys:

. . .

A foreign key must reference columns that either are a primary key or form a unique constraint. This means that the referenced columns always have an index (the one underlying the primary key or unique constraint); so checks on whether a referencing row has a match will be efficient.

https://mariadb.com/kb/en/sql-99/constraint_type-foreign-key-constraint/说:

A FOREIGN KEY Constraint is either a < Table Constraint> or a and defines a rule that constrains a foreign key to values that match only those values contained in a referenced unique key.


回复您的评论:

The idea is that each object will have collections of nodes associated with it and only one of nodes could be the root-node.

ALTER TABLE objects 
    ADD COLUMN root_node_id integer, 
    ADD CONSTRAINT objects_nodes_fkey 
    FOREIGN KEY (root_node_id) 
    REFERENCES nodes (node_id); 

这样每个对象都引用一个节点。无可否认,约束并不严格强制对象引用引用同一对象的节点。

如果你想达到这个水平的执法,你必须创建你问的是否必须的唯一约束。

+0

Bill,是否有一种方法来强制执行类似的约束(要求'root_node'来自同一个'object')以不同的(可能更有效的方式)?或者这是最好的方法? – Yatima

+0

@Yatima,考虑到你已经在对象表中冗余地存储root_node了。我的意思是,如果你引用了object_id,那么你就可以知道哪个root_node与该节点的object_id相关联。 –

+0

我不确定我是否遵循...这个想法是,每个对象都会有与其关联的'nodes'集合,并且只有一个节点可能是根节点。或者你看到更好的方法来做到这一点?我试着在这里问这个问题:http://stackoverflow.com/questions/40985510/what-is-best-design-for-one-to-many-relationship-with-back-references-to-each-ot但它看起来目前的方案是迄今为止最好的方法。顺便说一句,谢谢你写反面书,我学到了很多东西。 – Yatima

相关问题