You need to enable JavaScript to run this app. 如何实现两列至少一列非空的复合约束(Liquibase/PostgreSQL场景)
优惠活动
大模型
产品
解决方案
定价
更多

如何实现两列至少一列非空的复合约束(Liquibase/PostgreSQL场景)

两列至少一列非空的约束实现方案

这类约束本质是多列组合的业务校验规则,核心逻辑是对两个目标列做组合判断,只要任意一列存在有效业务值就允许数据入库,不属于单列NOT NULL的基础约束范畴,具体实现路径分三类说明:

Liquibase 工具的原生支持能力

Liquibase 从 3.5.0 版本开始就原生支持配置CHECK约束,不需要依赖自定义SQL就能直接落地这类跨列校验规则:

  • 配置时不需要逐列设置NOT NULL,只需要在changeSet中通过addCheckConstraint标签写入组合判断逻辑即可,示例配置参考:
    <changeSet id="chk_contact_at_least_one" author="data_ops">
        <addCheckConstraint
            tableName="sys_user"
            constraintName="chk_user_contact_valid"
            constrainedColumns="mobile,email"
            conditionConstraint="mobile IS NOT NULL OR email IS NOT NULL"
        />
    </changeSet>
    
  • 实际使用注意事项:低版本Liquibase(3.5.0之前)没有独立的CHECK约束配置入口,这类场景需要通过sql标签直接执行原生DDL语句实现约束创建;Liquibase透传CHECK逻辑时不会修改底层校验语法,只要目标数据库支持CHECK约束,就能保证约束逻辑正常生效。

通用SQL的实现方式

对于所有兼容SQL标准CHECK约束的数据库(包括PostgreSQL、MySQL 8.0.16及以上版本、SQL Server、Oracle等),都可以通过统一的ALTER语句创建这类约束,不存在数据库语法差异:

-- 通用约束创建语法
ALTER TABLE 目标业务表
ADD CONSTRAINT chk_两列至少一非空
CHECK (
  第一列 IS NOT NULL
  OR 第二列 IS NOT NULL
);

这类约束属于数据库内置的行级校验规则,在数据插入、更新时自动触发校验,不存在触发器类方案的性能开销,也不会因为运维操作误关校验逻辑导致脏数据入库。

PostgreSQL 专属的简化实现方式

PostgreSQL 在CHECK约束的基础上提供了更灵活的内置函数和语法,能简化多列非空判断的配置:

  • 对于列数较多的非空校验场景,可以直接用内置函数num_nonnulls自动统计多列中的非空值个数,不需要手写长串OR判断逻辑,比如要求mobile/email/wechat三列至少1个有效非空值,约束逻辑可以简化为:
    ALTER TABLE sys_user
    ADD CONSTRAINT chk_multi_contact_valid
    CHECK (num_nonnulls(mobile, email, wechat) >= 1);
    
  • 如果需要把“空字符串、纯空白字符串”也判定为无有效业务值,可以结合PostgreSQL的正则匹配语法调整校验逻辑,把非空判断和业务有效值判断结合,示例:
    ALTER TABLE sys_user
    ADD CONSTRAINT chk_contact_real_value
    CHECK (
      (mobile IS NOT NULL AND mobile !~ '^\s*$')
      OR (email IS NOT NULL AND email !~ '^\s*$')
    );
    
    相比通用SQL只能判断NULL的局限,这种写法能更贴合实际业务的校验要求。

内容的提问来源于stack exchange,提问作者LeYAUable

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.11.02 14:06:02