Ограничение на связанную таблицу

У меня есть 2 таблицы (ItemType и Item). ItemType имеет логическое значение hasSize, а таблица Item имеет столбец size.

Я хотел бы обеспечить, чтобы size устанавливалось только в том случае, если логическое значение hasSize = true.

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

Является ли это проблемой неидеального дизайна схемы или для этого есть подходящие решения?

ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
3
0
58
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

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

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

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

Что вы подразумеваете под выводом hasSize при запросе к базе данных? Мое первоначальное намерение состояло в том, чтобы ItemType (например, одежда) требовал, чтобы у связанных элементов был установлен столбец размера.

J3Y 30.05.2019 00:16

Правильно, тогда вы можете запросить тип элемента и определить таким образом, установлен ли размер.

Laurenz Albe 30.05.2019 01:28
Ответ принят как подходящий

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

Вот альтернативное решение, не использующее триггеры, где я накладываю проверочное ограничение на ОБНОВЛЯЕМЫЙ ВИД, чтобы предотвратить изменение данных в базовых таблицах, используя модификатор WITH CHECK OPTION. обратите внимание, что это будет проверяться только в том случае, если данные вставлены или обновлены через представление. Вы должны предоставить соответствующие разрешения, чтобы роль приложения не могла напрямую изменять таблицу item, но могла через UPDATABLE VIEW

Вот автономный скрипт с примерами данных и примерами вставки, которая не удалась, и вставки, которая прошла успешно.

-- set up dummy `item_type` table
CREATE TABLE item_type (
id int primary key generated by default as identity,
has_size bool,
name text not null unique
);
INSERT INTO item_type 
  (has_size, name) 
VALUES 
  (true, 'sizable type')
, (false, 'unisize');

-- set up dummy `item` table
CREATE TABLE item (
id int primary key generated by default as identity,
type_id int references item_type(id),
name text NOT NULL,
size text
);

INSERT INTO item
  (type_id, name, size)
VALUES
  (1, 'worlds best dad tee shirt', 'M')
, (2, 'usb key', NULL);

-- create updatable check view.
CREATE VIEW item_view AS
SELECT item.*
FROM item 
WHERE EXISTS (
SELECT 
FROM item_type 
WHERE item.type_id = item_type.id
  AND (item.size IS NOT NULL) = item_type.has_size
) 
WITH CASCADED CHECK OPTION; 
--    ^^^
-- i could have alternately used local 
-- instead of cascaded

Эта вставка не удастся

INSERT INTO item_view 
  (type_id, name, size) 
VALUES
  (2, 'dad socks', 'M');

Выдает следующую ошибку:

ERROR:  new row violates check option for view "item_view"
DETAIL:  Failing row contains (3, 2, dad socks, M).

Эта вставка получится

INSERT INTO item_view 
  (type_id, name, size) 
VALUES
  (2, 'dad socks', NULL);

SELECT * FROM item возвращает следующий результат, как и ожидалось

 id | type_id |           name            | size
----+---------+---------------------------+------
  1 |       1 | worlds best dad tee shirt | M
  2 |       2 | usb key                   |
  4 |       2 | dad socks                 |

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

J3Y 30.05.2019 01:22

@ J3Y, вы правы в отношении недостатка, однако вы можете отменить предикаты в запросе создания представления, чтобы пометить все строки, которые не соответствуют ограничению, и исправить их перед переносом базы данных для использования обновляемого представления. Я должен добавить, что если вы применяете ограничения, они должны быть двунаправленными, то есть вы также должны настроить обновляемое представление для item_type, которое предотвратит обновления поля has_size, если есть связанные items

Haleemur Ali 30.05.2019 03:57

Другие вопросы по теме