sql-server - 如何创建多表检查约束?

标签 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

协会

志愿者可以报名参加多个事件。
事件可能由多名志愿者组成。

一个事件可能有多个类次。
一次转变只属于一个事件。

一个类次可能只有一名志愿者。
一名志愿者可以轮类工作。

检查约束

  1. 我可以创建一个检查约束来 强制执行,不配备任何轮类人员 未报名的志愿者 那个转变的事件?

  2. 我可以创建一个检查约束来 强制执行两个重叠的类次 从来没有配备相同的人员 志愿者?

最佳答案

强制数据完整性的最佳位置是数据库。请放心,如果您允许,某些开发人员无论有意还是无意,都会找到一种方法将不一致的内容偷偷带入数据库!

这是一个带有检查约束的示例:

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);

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

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')

以下是表定义:

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)
)

关于sql-server - 如何创建多表检查约束?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2588072/

相关文章:

mysql - MySQL中的CHECK约束不起作用

sql - ORA-02290 : check constraint violated

mysql - MySQL 中的 CHECK 约束不起作用

sql - 如何创建一个约束来确保输入的日期总是 >= 今天或 future 的日期?

sql - 使用带有 WHERE 条件的单个查询 (SQL Express 2005) 从多个表中删除行

sql - 按 : 分区的 Row_Number() 性能优化

SQL Server – 获取仅在线购买的客户的行

sql - 如何创建一个 CHECK 约束,允许用户从今天起只输入 DateTime?

sql - 根据匹配列进行选择

sql-server - 如何让 NHibernate 停止使用 nvarchar(4000) 来插入参数字符串?