繁体   English   中英

Check 约束可以与另一个表相关吗?

[英]Can a Check constraint relate to another table?

假设我有一个名为ProjectTimeSpan的表(我没有,只是作为示例!)包含StartDateEndDate列。

我还有另一个名为SubProjectTimeSpan的表,它还包含名为StartDateEndDate的列,我想在其中设置一个Check 约束,使得无法将 StartDate 和 EndDate 设置为ProjectTimeSpan.StartDateProjectTimeSpan.EndDate的“外部”值

一种了解另一个表值的检查约束...

这可能吗?

为了回应您对 GSerg 的回答的评论,这里有一个使用函数的示例检查约束:

alter table YourTable
add constraint chk_CheckFunction
check (dbo.CheckFunction() = 1)

您可以在哪里定义函数,例如:

create function dbo.CheckFunction()
returns int
as begin
    return (select 1)
end

该函数允许引用其他表。

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

ProjectTimeSpan表的键与StartDateEndDate列组合成一个复合键,然后将此复合键用作您的SubProjectTimeSpan表中的外键引用。 这将使您能够在SubProjectTimeSpan表中编写必要的行级CHECK约束,例如

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

正如许多答案所示,您当然可以这样做。 但是,您应该知道 SQL Server 似乎对使用 UDF 的CHECK CONSTRAINT有问题:

https://dba.stackexchange.com/questions/12779/how-are-my-sql-server-constraints-being-bypassed

您需要在父表和子表上添加约束,因为子项目不能超出项目范围,但项目范围也不能移出所有子项目。

在这种情况下,您应该通过事务推迟对上层(Web 服务、应用程序)的约束检查,以确保在对两个表进行多次查询后您的数据处于有效状态!

这是绝对可能的,而且实际上非常简单。 根据你的例子:

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
)

但是请注意,这不会特别有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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