Как эмулировать теговое объединение в базе данных? - PullRequest
11 голосов
/ 13 ноября 2009

Как лучше всего эмулировать Tagged union в базах данных? Я говорю о чем-то вроде этого:

create table t1 {
  vehicle_id INTEGER NOT NULL REFERENCES car(id) OR motor(id) -- not valid
  ...
}

где идентификатор_транспорта автомобиля будет идентификатором в таблице автомобилей ИЛИ таблице двигателей, и он будет знать, какой именно.

(предположим, что столы двигателя и автомобиля не имеют ничего общего0

Ответы [ 3 ]

9 голосов
/ 13 ноября 2009

Некоторые люди используют для этого дизайн под названием Полиморфные ассоциации, позволяющий vehicle_id содержать значение, которое существует либо в car, либо motor таблицах. Затем добавьте vehicle_type, который называет таблицу, на которую ссылается данная строка в t1.

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

Лучший дизайн - заимствовать концепцию из ОО дизайна общего супертипа как car, так и motor:

CREATE TABLE Identifiable (
 id SERIAL PRIMARY KEY
);

Затем сделайте t1 ссылку на эту таблицу супертипа:

CREATE TABLE t1 (
  vehicle_id INTEGER NOT NULL,
  FOREIGN KEY (vehicle_id) REFERENCES identifiable(id)
  ...
);

А также сделайте так, чтобы подтипы ссылались на родительский супертип. Обратите внимание, что первичным ключом подтипов является , а не с автоинкрементом. Родительский супертип заботится о выделении нового значения id, а потомки ссылаются только на это значение.

CREATE TABLE car (
  id INTEGER NOT NULL,
  FOREIGN KEY (id) REFERENCES identifiable(id)
  ...
);

CREATE TABLE motor (
  id INTEGER NOT NULL,
  FOREIGN KEY (id) REFERENCES identifiable(id)
  ...
);

Теперь вы можете иметь истинную ссылочную целостность, но также поддерживать несколько таблиц подтипов со своими собственными атрибутами.


Ответ @Quassnoi также показывает способ применения непересекающихся подтипов . То есть вы хотите запретить ссылкам на car и motor одну и ту же строку в их родительской таблице супертипов. Когда я делаю это, я использую первичный ключ с одним столбцом для Identifiable.id, но также объявляю ключ UNIQUE вместо Identifiable.(id, type). Внешние ключи в car и motor могут ссылаться на уникальный ключ из двух столбцов вместо первичного ключа.

5 голосов
/ 13 ноября 2009
CREATE TABLE vehicle (type INT NOT NULL, id INT NOT NULL,
             PRIMARY KEY (type, id)
)

CREATE TABLE car (type INT NOT NULL DEFAULT 1, id INT NOT NULL PRIMARY KEY,
             CHECK(type = 1),
             FOREIGN KEY (type, id) REFERENCES vehicle
)

CREATE TABLE motorcycle (type INT NOT NULL DEFAULT 2, id INT NOT NULL PRIMARY KEY,
             CHECK(type = 2),
             FOREIGN KEY (type, id) REFERENCES vehicle
)

CREATE TABLE t1 (
  ...
  vehicle_type INT NOT NULL,
  vehicle_id INT NOT NULL,
  FOREIGN KEY (vehicle_type, vehicle_id) REFERENCES vehicle
  ...
)
3 голосов
/ 13 ноября 2009

Я думаю, вы могли бы смоделировать такую ​​ссылку, используя наследование таблиц в PostgreSQL .

Если вам действительно нужно знать, откуда берется строка в запросе, вы можете использовать простой UNION ALL, например (эта возможность не имеет ничего общего с наследованием таблиц):

SELECT car.*, 'car' table_name
UNION ALL
SELECT motor.*, 'motor' table_name
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...