この小さなデータベースを想像してみてください...
削除されたデッド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)
)
質問1は簡単です。 ShiftテーブルでEventVolunteerテーブルを直接参照するだけで、準備が整います。
私がすることは、EventIdとVolunteerIdのペアに一意の制約を付けて、自動インクリメントするEventVolunteerテーブルのIdentity列を作成することです。 Shiftテーブルへの外部キーとしてEventVolunteerId(ID)を使用します。これにより、データをある程度正規化しながら、必要な制約をかなり簡単に適用できます。
これはあなたの一般的な質問に対する答えではないことを理解していますが、これはあなたの特定の問題に対する最善の解決策だと思います。
編集:
私はその質問を完全に読むべきだった。このソリューションは、重複していなくても、1人のボランティアが同じイベントで2つのシフトを行うことを防ぎます。おそらく、シフトの開始時刻と終了時刻をEventVolunteerに移動し、そのテーブルの時刻にチェック制約を設定するだけで十分ですが、Shiftテーブルの外にシフトデータがあるため、直感的には聞こえません。