Условно ограничить поле таблицы от ссылки на другую таблицу? - PullRequest
0 голосов
/ 25 января 2019

У меня есть таблица бар

CREATE TABLE bar(
  bar_id serial,
  good_bar boolean,
  PRIMARY KEY (bar_id) );

и стол фу

CREATE TABLE foo (
  foo_id serial,
  side_a INTEGER REFERENCES bar(bar_id),
  side_b INTEGER REFERENCES bar(bar_id) 
  PRIMARY KEY (foo_id); 

Однако, если в foo.side_a используется запись "bar", я хочу запретить ее использование в foo.side_b и наоборот.

Ограничения PostgreSQL CHECK, по-видимому, ограничены столбцом, в который помещено ограничение, а составной первичный ключ (side_a, side_b) не обеспечивает покрытие для чего-то вроде

INSERT INTO foo(side_a,side_b) VALUES
(0, 1),
(1, 0);

что я хочу поднять какую-то ошибку.

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

РЕДАКТИРОВАТЬ для уточнения: Проблема с наличием одного столбца для ссылок bar_id заключается в том, что данные в таблице столбцов будут преобразованы (вне базы данных) в зависимости от того, какой стороне назначен bar_id.

Лучшая аналогия, которую я могу придумать, - это шахматные фигуры. Обе стороны будут иметь одинаковые фигуры, но о позициях этих фигур можно думать как с точки зрения белых (side_a), так и черных (side_b).

Существуют дополнительные подробности реализации, основанные на существовании двух различных перспектив для данных.

1 Ответ

0 голосов
/ 25 января 2019

Вам нужен уникальный индекс для выражения:

CREATE UNIQUE INDEX ON foo (greatest(side_a, side_b), least(side_a, side_b));

INSERT INTO foo(side_a,side_b) 
VALUES
    (1, 2),
    (2, 1);

ERROR:  duplicate key value violates unique constraint "foo_greatest_least_idx"
DETAIL:  Key ((GREATEST(side_a, side_b)), (LEAST(side_a, side_b)))=(2, 1) already exists.
...