Enforce maximum number of child rows

一世执手 提交于 2019-11-28 13:12:14

There is a way to do this without using triggers, but it's ugly code and I'm not sure if I'd ever recommend using it in anger.

This technique uses an indexed view to enforce the constraint. Normally, I'm perfectly happy to use indexed views to enforce constraints, certainly over and above using triggers to enforce constraints. But the issue here is that the error message that is produced when the constraint is violated makes no mention of any constraint names - you'll get an error message and have to know that the error message has been produced by a "booby-trap" in your database.

But here, for your viewing pleasure, is the view:

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)

And the error message it produces for the second insert:

Msg 8115, Level 16, State 2, Line 1
Arithmetic overflow error converting expression to data type int.
The statement has been terminated.

In case it's not obvious, this works by arranging for 4 * some magic number to be less than the maximum number that can be represented by an int, but 5 * that same magic number is higher than the maximum.

And so if there are 4 or less rows, the SUM() works, but if you attempt to have 5 or more rows, we get the error.


This technique could even be extended to having the maximum number of children allowed be separately configured for each parent. You'd store the maximum in the Parents table and also have a look-up table that, for each possible maximum, stored a usable magic number to use to enforce that maximum.


I worked out how to do this yesterday, and despite being sure that there are questions that ask this from time to time on SO, I couldn't find any instances, hence the new question & answer. As I say at the top of this answer though, I'm not sure if I'd actually do this in production code, or whether to just keep it around as a cute trick.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!