SQL - 如何使用用户定义的函数来约束 2 个表之间的值

Posted

技术标签:

【中文标题】SQL - 如何使用用户定义的函数来约束 2 个表之间的值【英文标题】:SQL - How do you use a user defined function to constrain a value between 2 tables 【发布时间】:2019-11-19 12:52:24 【问题描述】:

首先是相关代码:

create table customer(
   customer_mail_address   varchar(255)   not null,
   subscription_start      date           not null,
   subscription_end        date,          check (subscription_end !< subcription start)
   constraint pk_customer primary key (customer_mail_address)
)

create table watchhistory(
   customer_mail_address   varchar(255)   not null,
   watch_date              date           not null,
   constraint pk_watchhistory primary key (movie_id, customer_mail_address, watch_date)
)

alter table watchhistory
    add constraint fk_watchhistory_ref_customer foreign key (customer_mail_address)
        references customer (customer_mail_address)
    on update cascade
    on delete no action
go

所以我想使用 UDF 将 watchhistory 中的 watch_date 限制在 subscription_startsubscription_end 之间客户。我好像搞不懂。

【问题讨论】:

请添加您正在使用的rdms。例如,在 Oracle 上,您不能使用引用另一个表的检查约束:“检查约束的条件可以引用表中的任何列,但不能引用其他表的列。” 您使用的是哪个DBMS 产品? “SQL”只是一种查询语言,而不是特定数据库产品的名称(!&lt; 不是有效的 SQL 运算符)。请为您正在使用的数据库产品添加tag 我正在使用 Microsoft SQL Server Management Studio Can a Check constraint relate to another table?的可能重复 虽然您可以绕道而行,但更好的问题是您认为应该这样做的原因。 “历史”这个名称表明该表并不是您模型的真正组成部分,而是用于捕获不断变化的信息(可能用于审计或取证目的)。 【参考方案1】:

检查约束无法根据其他表验证数据,docs 说(强调我的):

[ CONSTRAINT constraint_name ]   
   
  ...
  CHECK [ NOT FOR REPLICATION ] ( logical_expression )  

逻辑表达式

是用于 CHECK 约束的逻辑表达式,返回 TRUE 或 错误的。与 CHECK 约束一起使用的logical_expression 不能 引用另一个表,但可以引用同一个表中的其他列 同一行的表。表达式不能引用别名数据 输入。

话虽如此,您可以创建一个标量函数来验证您的日期,并在检查条件上使用该标量函数:

CREATE FUNCTION dbo.ufnValidateWatchDate (
    @WatchDate DATE,
    @CustomerMailAddress VARCHAR(255))
RETURNS BIT
AS
BEGIN

    IF EXISTS (
        SELECT
            'supplied watch date is between subscription start and end'
        FROM
            customer AS C
        WHERE
            C.customer_mail_address = @CustomerMailAddress AND
            @WatchDate BETWEEN C.subscription_start AND C.subscription_end)
    BEGIN
        RETURN 1
    END

    RETURN 0

END

现在添加您的检查约束,以便验证函数的结果是否为 1:

ALTER TABLE watchhistory 
    ADD CONSTRAINT CHK_watchhistory_ValidWatchDate 
    CHECK (dbo.ufnValidateWatchDate(watch_date, customer_mail_address) = 1)

这不是指向另一个表的直接链接,而是您可以用来验证日期的解决方法。请记住,如果您在观察日期插入之后更新customer 日期,日期将不一致。在这种情况下,确保完全一致的唯一方法是使用几个触发器。

【讨论】:

以上是关于SQL - 如何使用用户定义的函数来约束 2 个表之间的值的主要内容,如果未能解决你的问题,请参考以下文章

sql中外键怎么写?

如何在 SQL Server 中使用级联删除?

pl sql使用3个表编写函数

(PL/)SQL 查看超过 3 个表,用户名和密码

是否可以将一个表中的主键引用为超过 2 个表的外键约束?

如何使用 Oracle SQL 约束检查酒店房间是不是已预订