2016-12-17 3 views
2

Я пытаюсь создать схему в PostgreSQL, которая будет содержать две таблицы, перекрестные ссылки друг на друга. Тем не менее, если не добавить избыточный UNIQUE constrain (см. Код ниже), я получаю ошибку: ERROR: there is no unique constraint matching given keys for referenced table "nodes".Почему это УНИКАЛЬНОЕ ограничение требуется?

Так что мой вопрос: почему это дополнительное уникальное ограничение необходимо и есть ли способ избежать его создания? (для уменьшения времени выполнения).

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.


Re ваш комментарий:

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' был из одного и того же объекта) в другом (возможно, более эффективном)? Или это лучший способ? – Yatima

+0

@ Yatima, считайте, что вы уже сохраняете root_node избыточно в таблице объектов. Я имею в виду, если вы ссылаетесь на object_id, тогда вы сможете указать, какой root_node связан с object_id этого узла. –

+0

Я не уверен, что я следую ... Идея состоит в том, что каждый объект будет иметь связанные с ним коллекции связанных с ним узлов, и только один из узлов может быть корневым узлом. Или вы видите лучший способ сделать это? Я попытался задать этот вопрос здесь: http://stackoverflow.com/questions/40985510/what-is-best-design-for-one-to-many-relationship-with-back-references-to-each-ot, но мне кажется, что нынешняя схема - лучший подход. Кстати, благодарю вас за то, что вы написали книгу антипартийнов - я многому научился ее читать! – Yatima

Смежные вопросы