Есть ли шаблон для объединения таблицы для разных предметов? - PullRequest
0 голосов
/ 16 мая 2018

Я хотел бы иметь комбинацию из двух столбцов на основе ограничения столбцов. Я не нахожу здесь способа использовать внешний ключ, потому что он должен быть условным FK. Надеюсь, что этот базовый SQL показывает проблему:

CREATE TABLE performer_type (
  id serial primary key,
  type varchar
);

INSERT INTO performer_type ( id, type ) VALUES (1, 'singer'), ( 2, 'band');

CREATE TABLE singer (
  id serial primary key,
  name varchar
);

INSERT INTO singer ( id, name ) VALUES (1, 'Robert');

CREATE TABLE band (
  id serial primary key,
  name varchar
);

INSERT INTO band ( id, name ) VALUES (1, 'Animates'), ( 2, 'Zed Leppelin');

CREATE TABLE gig (
  id serial primary key,
  performer_type_id int default null, /* FK, no problem */
  performer_id int default null       /* want FK based on previous FK, no good solution so far */
);

INSERT INTO gig ( performer_type_id, performer_id ) VALUES ( 1,1 ), (2,1), (2,2), (1,2), (2,3);

Теперь последний INSERT работает, но для последних 2 пар значений мне бы это не понравилось, потому что нет ни идентификатора певца 2, ни идентификатора группы 3. Как установить такое ограничение?

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

Я также нашел очень многообещающий паттерн , но это для меня с ног на голову, я так и не понял, как заставить его работать в моем случае.

То, что я здесь ищу, кажется мне настолько полезным паттерном, я думаю, что для этого должен быть какой-то общий путь. Это 1014 *

Edit.

Кажется, я выбираю плохие элементы в своих примерах, поэтому я стараюсь прояснить: между разными таблицами исполнителей (singer и band) есть NO отношение между ними. gig -таблица просто должна перечислять задачи для разных исполнителей, не устанавливая никаких отношений между ними.

В другом примере были бы товары на складе: у меня может быть item_type -таблица, которая определяет сотни типов предметов со связанными таблицами (например, orange и house), и должна быть таблица stock который зачисляет все виды предметов.

PostgreSQL, который я использую - 9,6

1 Ответ

0 голосов
/ 17 мая 2018

На основе @Laurenz Albe ответ Я формирую решение для примера выше.Основное отличие: есть родительская таблица performer, в которой PK является FK / PK для определенных таблиц исполнителей и на которую также ссылаются из таблицы gig.

CREATE TABLE performer_type (
  id serial primary key,
  type varchar
);
INSERT INTO performer_type ( id, type ) VALUES (1, 'singer' ), ( 2, 'band' );

CREATE TABLE performer (
  id serial primary key,
  performer_type_id int REFERENCES performer_type(id)
);

CREATE TABLE singer (
  id int primary key REFERENCES performer(id),
  name varchar
);

INSERT INTO performer ( performer_type_id ) VALUES (1); -- get PK 1 for next statement
INSERT INTO singer ( id, name ) VALUES (1, 'Robert');

CREATE TABLE band (
  id int primary key REFERENCES performer(id),
  name varchar
);

INSERT INTO performer ( performer_type_id ) VALUES (2); -- get PK 2 for next statement
INSERT INTO singer ( id, name ) VALUES (2, 'Animates');
INSERT INTO performer ( performer_type_id ) VALUES (2); -- get PK 3 for next statement
INSERT INTO singer ( id, name ) VALUES (3, 'Zed Leppelin');

CREATE TABLE gig (
  id serial primary key,
  performer_id int REFERENCES performer(id)
);

INSERT INTO gig ( performer_id ) VALUES (1), (2), (3), (4);

И последний INSERT завершается неудачно, как и ожидалось:

ERROR:  insert or update on table "gig" violates foreign key constraint "gig_performer_id_fkey"
DETAIL:  Key (performer_id)=(4) is not present in table "performer".

Но

Для меня есть досадная проблема: у меня нет хорошего способа разграничить, какой ID для певца, а какой для группы и т. Д. (ВВ оригинальном примере у меня была performer_type_id в gig -таблице для этого), потому что любой performer_id может принадлежать любому исполнителю.Поэтому я хотел бы, чтобы у любого типа исполнителя был свой собственный диапазон идентификаторов, поэтому я создаю фиктивную таблицу для каждой последовательности

CREATE TABLE band_id (
  id int primary key,
  dummy boolean default null
);
CREATE SEQUENCE band_id_seq START 1;
ALTER TABLE band_id ALTER COLUMN id SET DEFAULT nextval('band_id_seq');

CREATE TABLE singer_id (
  id int primary key,
  dummy boolean default null
);
CREATE SEQUENCE singer_id_seq START 2000000;
ALTER TABLE singer_id ALTER COLUMN id SET DEFAULT nextval('singer_id_seq');

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

INSERT INTO band_id (dummy) VALUES (NULL);

Попытка выяснить, возможно ли решить этот процесс на уровне БД, или есть что-то сделать на уровне приложения.Было бы хорошо, если бы вставка в таблицу band могла бы:

  • до вставки триггера в band_id, чтобы сгенерировать конкретный идентификатор
  • , прежде чем вставка триггера в этот новый идентификатор в performer-table
  • включить этот новый идентификатор в INSERT в band

Фрист 2 точки просты, но последняя точка пока не ясна.

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