如何创建多表检查约束?

Zac*_*son 27 sql-server check-constraints

请想象这个小型数据库......

删除死了ImageShack链接 - 志愿者数据库图

Volunteer     Event         Shift         EventVolunteer
=========     =====         =====         ==============
Id            Id            Id            EventId
Name          Name          EventId       VolunteerId
Email         Location      VolunteerId
Phone         Day           Description
Comment       Description   Start
                            End
Run Code Online (Sandbox Code Playgroud)

协会

志愿者可以报名参加多个活动.
活动可能由多名志愿者组成.

事件可能有多个班次.
转变只属于一个事件.

轮班可能只有一名志愿者.
志愿者可以多班次.

检查约束

  1. 我是否可以创建一个检查约束来强制执行没有班次的志愿者没有为该班次活动注册?

  2. 我是否可以创建一个检查约束来强制执行两个重叠的班次从未由同一个志愿者配备?

And*_*mar 35

实施数据完整性的最佳位置是数据库.请放心,有些开发人员,无论是否有意,都会找到一种方法将不一致的东西隐藏到数据库中,如果你让它们出现的话!

以下是检查约束的示例:

CREATE FUNCTION dbo.SignupMismatches()
RETURNS int
AS BEGIN RETURN (
    SELECT count(*)
    FROM Shift s
    LEFT JOIN EventVolunteer ev
    ON ev.EventId = s.EventId
    AND ev.VolunteerId = s.VolunteerId
    WHERE ev.Id is null
) END
go
ALTER TABLE Shift ADD CONSTRAINT chkSignup CHECK (dbo.SignupMismatches() = 0);
go
CREATE FUNCTION dbo.OverlapMismatches()
RETURNS int
AS BEGIN RETURN (
    SELECT count(*)
    FROM Shift a
    JOIN Shift b
    ON a.id <> b.id
    AND a.Start < b.[End]
    AND a.[End] > b.Start
    AND a.VolunteerId = b.VolunteerId
) END
go
ALTER TABLE Shift ADD CONSTRAINT chkOverlap CHECK (dbo.OverlapMismatches() = 0);
Run Code Online (Sandbox Code Playgroud)

以下是新数据完整性检查的一些测试:

insert into Volunteer (name) values ('Dubya')
insert into Event (name) values ('Build Wall Around Texas')

-- Dubya tries to build a wall, but Fails because he's not signed up
insert into Shift (VolunteerID, EventID, Description, Start, [End]) 
    values (1, 1, 'Dunbya Builds Wall', '2010-01-01', '2010-01-02')

-- Properly signed up?  Good
insert into EventVolunteer (VolunteerID, EventID) 
    values (1, 1)
insert into Shift (VolunteerID, EventID, Description, Start, [End]) 
    values (1, 1, 'Dunbya Builds Wall', '2010-01-01', '2010-01-03')

-- Fails, you can't start the 2nd wall before you finished the 1st
insert into Shift (VolunteerID, EventID, Description, Start, [End]) 
    values (1, 1, 'Dunbya Builds Second Wall', '2010-01-02', '2010-01-03')
Run Code Online (Sandbox Code Playgroud)

以下是表定义:

set nocount on
if OBJECT_ID('Shift') is not null
    drop table Shift
if OBJECT_ID('EventVolunteer') is not null
    drop table EventVolunteer
if OBJECT_ID('Volunteer') is not null
    drop table Volunteer
if OBJECT_ID('Event') is not null
    drop table Event
if OBJECT_ID('SignupMismatches') is not null
    drop function SignupMismatches
if OBJECT_ID('OverlapMismatches') is not null
    drop function OverlapMismatches

create table Volunteer (
    id int identity primary key
,   name varchar(50)
)
create table Event (
    Id int identity primary key
,   name varchar(50)
)
create table Shift (
    Id int identity primary key
,   VolunteerId int foreign key references Volunteer(id)
,   EventId int foreign key references Event(id)
,   Description varchar(250)
,   Start datetime
,   [End] datetime
)
create table EventVolunteer (
    Id int identity primary key
,   VolunteerId int foreign key references Volunteer(id)
,   EventId int foreign key references Event(id)
,   Location varchar(250)
,   [Day] datetime
,   Description varchar(250)
)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,我们在检查约束中使用UDF遇到了一些麻烦.读者可能想要查看[我的SQL Server约束如何被绕过?](http://stackoverflow.com/questions/7756268/how-are-my-sql-server-constraints-being-bypasssed),然后才能走这条路线. (5认同)