Обеспечить равенство типов внешних ключей в Postgres - PullRequest
0 голосов
/ 04 декабря 2018

У меня есть таблица сущностей с несколькими типами сущностей и таблица отношений сущностей, которая должна обеспечивать, чтобы она содержала только отношения между сущностями одного типа.

В настоящее время у меня есть два подхода к этому:

  1. CREATE TABLE entity (
      id uuid PRIMARY KEY,
      type my_enum_type NOT NULL,
      -- … more 
    );
    
    CREATE TABLE relation (
      id uuid PRIMARY KEY,
      x uuid REFERENCES entity NOT NULL,
      y uuid REFERENCES entity NOT NULL,
      CHECK(entity(x).type = entity(y).type)
      -- Doesn't work because CHECK cannot reference other tables.
    );
    
  2. К счастью, в настоящее время у меня есть только два типа, и я не ожидаю, что это скоро изменится.Но наследование плохо сочетается с внешними ключами, поэтому оно становится довольно многословным:

    CREATE TABLE entity (
      id uuid PRIMARY KEY,
      -- … more fields
    );
    CREATE TABLE entity_a (
      PRIMARY KEY (id)
    ) INHERITS (entity);
    CREATE TABLE entity_b (
      PRIMARY KEY (id)
    ) INHERITS (entity);
    
    CREATE TABLE relation (
      id uuid PRIMARY KEY,
      x uuid NOT NULL,
      y uuid NOT NULL,
      -- … more fields
    );
    CREATE TABLE relation_a (
      PRIMARY KEY (id),
      FOREIGN KEY (x) REFERENCES entity_a (id),
      FOREIGN KEY (y) REFERENCES entity_a (id)
    ) INHERITS (relation);
    CREATE TABLE relation_b (
      PRIMARY KEY (id),
      FOREIGN KEY (x) REFERENCES entity_b (id),
      FOREIGN KEY (y) REFERENCES entity_b (id)
    ) INHERITS (relation);
    

Второй подход определенно имеет то преимущество, что он работает, но он многословный, не расширяемый, иединственное преимущество перед полностью отдельными определениями таблиц состоит в том, что они избегают копирования всех дополнительных полей (а затем, возможно, забывают обновить их в обоих местах).

Есть предложения о том, как решить эту проблему более элегантно?

1 Ответ

0 голосов
/ 04 декабря 2018

Следующие операторы добавят ограничения к вашему решению 1), чтобы условие всегда выполнялось:

/* we need a (redundant) UNIQUE constraint as target for foreign keys */
ALTER TABLE entity ADD UNIQUE (type, id);

/* add a (redundant) "type" column and fill it from "entity" */
ALTER TABLE relation ADD type my_enum_type;

UPDATE relation SET type = e.type
   FROM entity AS e
   WHERE relation.x = e.id;

ALTER TABLE relation ALTER type SET NOT NULL;

/* now we can add foreign keys that guarantee your condition */
ALTER TABLE relation ADD FOREIGN KEY (type, x) REFERENCES entity (type, id);
ALTER TABLE relation ADD FOREIGN KEY (type, y) REFERENCES entity (type, id);

/* remove the bloat (optional) */
VACUUM (FULL) relation;

Правда, это добавляет избыточный столбец и избыточное ограничение, но я думаю, что это наиболееэлегантный и естественный способ обеспечить ваше состояние.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...