【问题标题】:Check constraint with multiple conditions and other table column referring检查具有多个条件和其他表列引用的约束
【发布时间】:2021-03-18 20:30:55
【问题描述】:

我有两个名为 tbl_1 和 tbl_2 的表,其架构如下

CREATE TABLE tbl_1(id int, disabled bit, qtype int)

CREATE TABLE tbl_2 (qtype int, qname nvarchar(MAX))

我想给 tbl_1 添加一个约束,这样如果(disabled=0 或 disabled 为 null)qtype 必须是 tbl_2.qtype 列中存在的数字?

我尝试创建一个函数并添加了一个检查约束

CREATE FUNCTION fn_Check_qtype(@qtype INT)
RETURNS int 
AS
BEGIN
IF EXISTS(SELECT qtype from tbl_1 where (disabled=0 or disabled is null) and qtype=@qtype)
IF EXISTS (SELECT qtype FROM tbl_2 WHERE qtype is not null and qtype = @qtype)
      return 1
  return 0
END

约束

alter table tbl_1
add constraint ck_qtyppe
check (dbo.fn_Check_qtype(qtype) =1)

但即使没有不匹配的记录也会抛出错误

ALTER TABLE 语句与 CHECK 约束冲突 “ck_qtype”。数据库“TestDB”中发生冲突,表 “dbo.tbl_1”,列“qtype”。

但如果我从 tbl_1 中删除 qtype null 值,则无论 disabled=0、disabled=、disabled = null 都可以。

【问题讨论】:

  • 第一个if exists 语句没有意义,因为它在整个表上运行。为什么不是外键约束?
  • 只有在插入或修改特定表中的行时才检查约束。在这样的关系中,您需要双向检查,对吗?认真思考你选择的道路。懒惰的编码/设计不会帮助你。我想不出为什么disabled 应该可以为空 - 你可以吗?某事存在或不存在 - 不应有“不知道但将其视为 xxx”的解释(可能会根据上下文而变化)。
  • 你可能会觉得stackoverflow.com/questions/65825778/… 很有趣,它对多表约束有更好的解决方案

标签: sql sql-server


【解决方案1】:

首先,外键引用应该是主键,所以让我假设tbl_2 定义为:

CREATE TABLE tbl_2 (
    qtype int primary key,
    qname nvarchar(MAX)
);

然后,您可以在没有用户定义函数的情况下执行此操作。您只需要一个持久的计算列:

CREATE TABLE tbl_1 (
    id int, 
    disabled bit,
    qtype int,
    qtype_enabled as (case when disabled = 1 then qtype end) persisted,
    foreign key (qtype_enabled) references tbl_2 (qtype)
);

Here 是一个 dbfiddle。

【讨论】:

  • 谢谢戈登!假设我们有两列而不是一个 CREATE TABLE tbl_1(id int, disabled bit, isdaily bit, qtype int) 并且我想向 tbl_1 添加一个约束,以便如果 isdaily = 1 并且 (disabled=0 或 disabled 为 null) qtype 必须是存在于 tbl_2.qtype 列中的数字。在这种情况下有什么解决方案?
  • FK 可以与唯一约束或主约束相关联——尽管前者很少使用。
  • @KishorKumar 。 . .这回答了这里提出的问题。新问题应该作为问题而不是评论提出。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多