Can a Check constraint relate to another table?
Let's say I have one table called ProjectTimeSpan (which I haven't, just as an example!) containing the columns StartDa开发者_C百科te and EndDate.
And that I have another table called SubProjectTimeSpan, also containing columns called StartDate and EndDate, where I would like to set a Check constraint that makes it impossible to set StartDate and EndDate to values "outside" the ProjectTimeSpan.StartDate to ProjectTimeSpan.EndDate
Kind of a Check constraint that knows about another tables values...
Is this possible?
In response to your comment on GSerg's answer, here's an example check constraint using a function:
alter table YourTable
add constraint chk_CheckFunction
check (dbo.CheckFunction() = 1)
Where you can define the function like:
create function dbo.CheckFunction()
returns int
as begin
return (select 1)
end
The function is allowed to reference other tables.
You can create a user-defined function that does the check and returns 1 or 0, then create a check
constraint on it, providing project id and the dates as the parameters.
Make a compound key of the ProjectTimeSpan
table's key combined with the StartDate
and EndDate
columns, then use this compound key for your foreign key reference in your SubProjectTimeSpan
table. This will give you the ability to write the necessary row-level CHECK
constraints in the SubProjectTimeSpan
table e.g.
CREATE TABLE ProjectTimeSpan
(
project_ID INTEGER NOT NULL UNIQUE, -- key
StartDate DATE NOT NULL,
EndDate DATE NOT NULL,
CHECK (StartDate < EndDate),
UNIQUE (project_ID, StartDate, EndDate) -- compound key
-- other project columns here...
);
CREATE TABLE SubProjectTimeSpan
(
project_ID INTEGER NOT NULL,
StartDate DATE NOT NULL,
EndDate DATE NOT NULL,
FOREIGN KEY (project_ID, StartDate, EndDate)
REFERENCES ProjectTimeSpan (project_ID, StartDate, EndDate)
ON DELETE CASCADE
ON UPDATE CASCADE,
sub_StartDate DATE NOT NULL,
sub_EndDate DATE NOT NULL,
CHECK (sub_StartDate < sub_EndDate),
CHECK (StartDate <= sub_StartDate), -- sub project can't start before main project
CHECK (sub_EndDate <= EndDate) -- sub project can't end after main project
-- other sub project columns here...
);
You certainly can do this as many answers have shown. However, you should be aware that SQL Server seems to have trouble with CHECK CONSTRAINT
s that use UDFs:
https://dba.stackexchange.com/questions/12779/how-are-my-sql-server-constraints-being-bypassed
You need to add constraint on the parent and the children table because the subproject can't be out of the project range but the project range can't move out of all the subproject too.
In these kind of situations, you should defer the check of the constraint on an upper level (webservice, application) with a transaction to ensure your data are in a valid state after multiple query on both table !
It is absolutely possible, and actually quite simple. As per your example:
create or alter function dbo.Check_SubProjectTimeSpan_ProjectTimeSpan_Dates(
@ProjectTimeSpanId int
, @StartDate date
, @EndDate date
)
returns bit
as
begin
if exists (select *
from dbo.ProjectTimeSpan as pts
where pts.Id = @ProjectTimeSpanId
and pts.StartDate >= @StartDate
and pts.EndDate <= @EndDate)
begin
return 1
end
return 0
end
go
alter table dbo.SubProjectTimeSpan add constraint
CK_SubProjectTimeSpan_ProjectTimeSpan_ProjectTimeSpanId_StartDate_EndDate
check (
dbo.Check_SubProjectTimeSpan_ProjectTimeSpan_Dates(
ProjectTimeSpanId, StartDate, EndDate) = 1
)
Please be aware however, that this will not be particularly performant.
精彩评论