【问题标题】:Adding an one-out-of-two not null constraint in postgresql在 postgresql 中添加二选一非空约束
【发布时间】:2011-07-23 19:16:36
【问题描述】:

如果我在 Postgresql 中有一个表:

create table Education ( 
    id                  integer references Profiles(id),
    finished            YearValue not null,
    started             YearValue,
    qualification       text,
    schoolName          text,
    studiedAt           integer references Organizations(id),
    primary key (id)
);

我需要做一个约束,使schoolNamestudiedAt 不能为空(其中一个必须包含信息)。

我该怎么做?

【问题讨论】:

    标签: sql postgresql constraints database-schema


    【解决方案1】:

    您可以使用check constraint,例如

    constraint chk_education check (schoolName is not null or studiedAt is not null)
    

    来自手册:

    检查约束是最通用的约束类型。它允许您指定某个列中的值必须满足布尔(真值)表达式。

    编辑:遵守 Pithyless 解释的替代方案:

    constraint chk_education check ((schoolName is not null and studiedAt is null) or (schoolName is null and studiedAt is not null))
    

    【讨论】:

    • 这项检查并不能防止同时设置 schoolName 和 studyAt ,我认为 OP 也考虑到了这一点。
    • 该问题要求一个不变量,它至少强制 schoolNamestudiedAt 包含一些信息。尽管我不同意对问题的解释,但我添加了一个符合您评论的约束变体。
    • 有点晚了,但这是一个异或约束,所以你可以将其表示为CHECK((schoolName IS NULL) <> (studiedAt IS NULL))
    • 如果表已经存在,您可以使用:ALTER TABLE Education ADD CONSTRAINT chk_schoolName_studiedAt CHECK ((schoolName IS NULL) <> (studiedAt IS NULL))
    【解决方案2】:

    您还可以在更新和插入时使用触发器,以在允许数据进入表之前检查是否遵循规则。当检查约束需要更复杂的逻辑时,通常会使用这种方法。

    【讨论】:

    • 警告:最好不要强制执行约束,而不是诉诸触发器
    • 我不会说不强制约束比使用触发器更好,我可能会说相反。使用触发器时,请始终牢记性能并明智地使用它们。不要为了它而使用它们。测试它们以满足您的特定需求,如果它允许您满足您的需求,那就去做吧。使用触发器没有内在的邪恶。这是盒子里的另一个工具。
    • 我猜这是debated before。我对它们的抱怨是它们不会对现有数据强制执行规则,并且通常有一些方法可以绕过它们来获取数据而不触发它们(例如,用于 Oracle 的 sql*loader)。鉴于此,具有良好定义事务的 api 提供的数据完整性不亚于任何副作用(以及更多好处)
    猜你喜欢
    • 1970-01-01
    • 2018-05-28
    • 1970-01-01
    • 2013-12-21
    • 2016-01-18
    • 1970-01-01
    • 2013-08-26
    • 2018-02-20
    • 1970-01-01
    相关资源
    最近更新 更多