Ответ 1
Существует три основных способа решения этой проблемы, поскольку ограничения CHECK не могут быть основаны на запросе.
Вариант 1: Триггеры
Самый простой подход - это поставить триггер на TANK, который запрашивает TANKS и генерирует исключение, если LEVEL превышает CAPACITY. Проблема с подобным упрощенным подходом заключается в том, что почти невозможно корректно обрабатывать проблемы concurrency. Если сеанс 1 уменьшает CAPACITY, тогда сеанс 2 увеличивает уровень, а затем обе транзакции фиксируют, триггеры не смогут обнаружить нарушение. Это может быть проблемой, если одна или обе таблицы редко изменяются, но в целом это будет проблемой.
Вариант 2: материализованные представления
Вы можете решить проблему concurrency, создав материализованное представление ON COMMIT, которое присоединяется к таблице TANK и TANKS, а затем создает ограничение CHECK для материализованного представления, которое проверяет, что LEVEL <= CAPACITY. Вы также можете избежать хранения данных дважды, если материализованное представление содержит только данные, которые будут нарушать ограничение. Для этого потребуются материализованные журналы просмотра на обеих базовых таблицах, которые добавят немного накладных расходов для вставки (хотя и меньше, чем использование триггеров). Нажатие проверки на время фиксации решит проблему concurrency, но она представляет собой небольшую проблему с управлением исключениями, так как операция COMMIT может завершиться неудачно, потому что материализованное обновление представления не сработало. Ваше приложение должно будет иметь возможность справиться с этой проблемой и предупредить пользователя об этом.
Вариант 3. Изменение модели данных
Если у вас есть значение в таблице A, которое зависит от предела в таблице B, это может указывать на то, что предел в B должен быть атрибутом таблицы A (вместо или в дополнение к атрибуту таблицы B), Конечно, это зависит от специфики вашей модели данных, но ее часто стоит рассмотреть.