简体   繁体   中英

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 StartDate 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.

您可以创建一个用户定义的函数来执行检查并返回 1 或 0,然后在其上创建一个check约束,提供项目 ID 和日期作为参数。

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 eg

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM