Есть способ сделать это без использования триггеров, но это уродливый код, и я не уверен, что буду рекомендовать его использовать в гневе.
Этот метод использует индексированное представление для обеспечения соблюдения ограничения. Обычно я совершенно счастлив использовать индексированные представления для обеспечения соблюдения ограничений, безусловно, помимо использования триггеров для обеспечения соблюдения ограничений. Но проблема здесь в том, что сообщение об ошибке, которое создается при нарушении ограничения, не упоминает никаких имен ограничений - вы получите сообщение об ошибке и должны знать, что сообщение об ошибке было создано "ловушкой" в вашей базе данных.
Но вот, для вашего удовольствия, вид:
create view dbo.DRI_Parent_Child_Maximum4
with schemabinding
as
select ParentID,COUNT_BIG(*) as Cnt,
SUM(536870911) as Meaningless
from dbo.Children
group by ParentID
go
create unique clustered index IX_DRI_Parent_Child_Maximum4
on dbo.DRI_Parent_Child_Maximum4(ParentID)
И сообщение об ошибке, которое он выдает для второй вставки:
Msg 8115, Level 16, State 2, Line 1
Arithmetic overflow error converting expression to data type int.
The statement has been terminated.
В случае, если это не очевидно, это работает, устраивая 4 * некоторое магическое число меньше, чем максимальное число, которое может быть представлено int
, но 5 * то же самое магическое число больше, чем максимум.
Итак, если есть 4 или меньше строк, SUM()
работает, но если вы попытаетесь иметь 5 или более строк, мы получим ошибку.
Этот метод можно даже расширить, чтобы максимальное количество дочерних элементов можно было настроить отдельно для каждого родителя. Вы должны хранить максимум в таблице Parents
, а также иметь справочную таблицу, в которой для каждого возможного максимума хранится полезное магическое число, используемое для обеспечения соблюдения этого максимума.
Я решил, как это сделать вчера, и, несмотря на то, что я был уверен, что время от времени возникают вопросы, которые задают это на SO, я не смог найти ни одного экземпляра, отсюда и новый вопрос и ответ. Однако, как я сказал в начале этого ответа, я не уверен, действительно ли я сделал бы это в производственном коде или просто оставил бы его как симпатичный трюк.
person
Damien_The_Unbeliever
schedule
07.05.2014