Что ограничивает область действия ограничения CHECK при проверке межстрочного правила?
CHECK проверяет условие для изменяемой строки, а не произвольное состояние всей таблицы. Поэтому он подходит для правил внутри одной строки, но не выражает надежно ограничения, зависящие от наличия, количества или значений других строк.
Реляционная модель разделяет ограничения домена и ограничения целостности отношения. SQL получил механизм CHECK прежде всего для проверки допустимости значений отдельного кортежа: диапазонов, обязательных зависимостей между столбцами и других локальных условий.
Для межстрочных правил стандарт SQL предусматривает более общую идею утверждений, или ASSERTION. Однако этот механизм практически не поддерживается большинством распространённых СУБД, поэтому на практике применяют ключи, внешние ключи, специальные ограничения, триггеры или изменение структуры данных.
Предположим, бизнес-правило требует, чтобы у клиента одновременно существовала не более одной активной подписки. Проверка должна учитывать другие строки того же клиента, а не только значения в новой или изменённой строке.
Попытка решить такое правило обычным CHECK либо невозможна средствами стандартного ограничения, либо приводит к ошибочному представлению о его гарантиях. Даже если приложение сначала ищет существующую подписку, параллельные транзакции могут одновременно пройти эту проверку и создать дубликаты.
Ограничение CHECK оценивается в контексте проверяемой строки при её вставке или изменении. Оно не является общим запросом к таблице и не предназначено для подсчёта других строк или проверки отсутствия совпадений во всём отношении.
Для локального правила вроде «дата окончания не раньше даты начала» CHECK является подходящим инструментом. Для межстрочного правила нужно выбрать механизм, который действительно видит согласованное состояние нескольких строк:
Важно различать проверку и гарантию. Запрос из приложения перед вставкой может обнаружить нарушение в текущем снимке данных, но без подходящей блокировки или ограничения две конкурентные транзакции способны получить одинаковый результат проверки. Надёжное правило должно контролироваться на уровне базы данных с учётом конкурентного доступа.
В сервисе бронирования нужно запретить пересечение интервалов для одного ресурса. Проверка в приложении сначала ищет пересекающееся бронирование, но два параллельных запроса могут одновременно не найти конфликт и оба записать интервалы.
Вариант с CHECK не подходит: пересечение зависит от других строк и интервалов. Вариант с триггером выражает правило, но усложняет блокировки и тестирование; при ошибочной изоляции гонка всё ещё возможна. Вариант с отдельными дискретными слотами позволяет задать уникальность по ресурсу и слоту, но требует изменения модели и подходит только для дискретного времени.
Если бизнес допускает дискретные слоты, предпочтителен последний вариант: межстрочное правило преобразуется в ограничение уникальности, которое СУБД проверяет атомарно. Для произвольных интервалов выбирают поддерживаемый СУБД механизм исключающих ограничений либо тщательно реализованный триггер с корректной синхронизацией.
В стандартной модели SQL CHECK не является механизмом для произвольного подзапроса по таблице. Даже если конкретная СУБД допускает нестандартное расширение, такое решение может иметь ограничения по моменту проверки, конкурентному доступу и переносимости. Для общего межстрочного утверждения следует использовать подходящий объект целостности, а не маскировать его под CHECK.
Потому что проверка и запись могут выполняться конкурентно. Две транзакции могут одновременно увидеть, что конфликтующей строки нет, после чего обе вставят свои строки. Гарантию даёт атомарное ограничение базы данных или явно согласованная схема блокировок и транзакций, а не сам факт предварительного SELECT.
Нет. Сначала следует проверить, можно ли выразить его ключом или внешним ключом. Например, правило «у каждого клиента только одна текущая запись» иногда моделируют отдельной таблицей текущих состояний с уникальным идентификатором клиента. Триггер нужен, когда правило нельзя свести к поддерживаемому ограничению, но он сложнее для сопровождения и требует анализа транзакционной конкуренции.