views:

45

answers:

3

Let´s say I have one table called ProjectTimeSpan (which I haven´t, just as 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?

+1  A: 

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.

GSerg
And how would that check constraint look like?
Jack Johnstone
@Jack `check (dbo.IsValidRange(project_id, start_date, end_date) = 1)`
GSerg
Very nice indeed. Thanks!
Jack Johnstone
GSerg: Presumably you would have to have a `CHECK` constraint using this UDF on *both* tables...? Please post some example code.
onedaywhen
@onedaywhen Yes, provided you want to change the parent project dates later. Which I could never imagine could be the case. See my comment to your answer.
GSerg
@GSerg: "change the parent project dates... I could never imagine could be the case" -- As a project manager myself I can assure you that the `EndDate` will change ;)
onedaywhen
A: 

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.

Andomar
and if I in the function wants to relate to an existing table like "ProjectTimeSpan.StartDate" I would put it like...?
Jack Johnstone
@Jack Johnstone: Just change the `select 1` part? You can pass parameters to the function
Andomar
Ok, I see - thanks!
Jack Johnstone
+1  A: 

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...
);
onedaywhen
Yes, this seems very straight forward! I think I actually in my mind was looking for something like "REFERENCES". Will check this out. Thanks!
Jack Johnstone
This only makes sense if you want to allow changing the parent project dates... which does not make sense. Consider: A main project, taking 1 month to complete. Because of the financial crysis (sic) you had to delay it (both `startdate` and `enddate` must get +1 month). But you can't do it, because then the check on a child project will fail (child dates now outside parent dates). And you can't change the child project dates before changing its parents dates. Deadlock.
GSerg