强制执行最大子行数

时间:2014-05-07 06:51:26

标签: sql-server referential-integrity

如果一个数据库有一对典型的“父和子”方式的表,有没有办法强制(不使用触发器)每个父母只能有一个最多,比如四个孩子?

所以我们有一个父母表:

create table dbo.Parents (
    ParentID char(2) not null primary key
    /* Yada Yada Yada */
)

和儿童表:

create table dbo.Children (
    ChildID char(2) not null primary key,
    ParentID char(2) not null references dbo.Parents (ParentID)
    /* usw */
)

我们填写了“父母”表:

insert into Parents (ParentID) values ('aa'),('bb')

我希望此插入成功:

insert into Children (ChildID,ParentID) values
('a1','aa'),('a2','aa'),('a3','aa')

但是这个插入失败了:

insert into Children (ChildID,ParentID) values
('b1','bb'),('b2','bb'),('b3','bb'),('b4','bb'),('b5','bb')

1 个答案:

答案 0 :(得分:4)

这是一种不使用触发器的方法,但它的代码很丑陋,而且我不确定我是否会建议在愤怒中使用它。

此技术使用indexed view来强制执行约束。通常情况下,我非常乐意使用索引视图来强制执行约束,当然使用触发器来强制执行约束。但是这里的问题是违反约束时产生的错误消息没有提到任何约束名称 - 您将收到错误消息并且必须知道错误消息是由&#34产生的;诱杀"在你的数据库中。

但是,在这里,为了您的观赏乐趣,是观点:

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上提出这个问题,但我无法找到任何实例,因此新问题&回答。正如我在这个答案的顶部所说,我不确定我是否真的在生产代码中这样做,或者是否只是将它作为一个可爱的技巧保留。