在 PostgreSQL 中,如何使 A 列或 B 列必须为非空?

use*_*516 14 postgresql database-design

我有一个带有“电子邮件地址”和“P2PMail 地址”列的表格。用户需要输入电子邮件或 P2PMail 地址。

如果我将两者都设置为NOT NULL,则必须同时填写两者才能创建记录。

如果我允许两者都为NULL,那么用户将完全无法访问。

如果我UNIQUE CONSTRAINT在两列上都设置了 a ,那么它们的组合必须是唯一的,但它并没有说明我想要做什么......除非我在这里思考错误。

实现这一目标的正确方法是什么?我担心答案是令人不快的东西,例如“触发器”之类的东西。(我从不习惯使用这些。)

Col*_*art 24

您需要一个表级检查约束:

alter table <name>
  add constraint either_email
    check (email is not null or p2pmail is not null);
Run Code Online (Sandbox Code Playgroud)

如果您只被允许输入一个,但不能同时输入:

alter table <name>
  add constraint either_email
    check (email is null <> p2pmail is null);
Run Code Online (Sandbox Code Playgroud)

第二种形式乍一看可能有点令人困惑:它的作用是比较两列的空状态——它们不允许相同。

约束也可以与表同时创建:

create table <name> (
  ... columns ...
  constraint either_email check (email is not null or p2pmail is not null)
);
Run Code Online (Sandbox Code Playgroud)

  • SQL 标准定义了`&lt;不等于运算符&gt; ::= &lt;&gt;`。我认为,只要没有令人信服的理由,就坚持使用标准 SQL 是个好主意。一方面,它将使答案适用于其他数据库。 (10认同)
  • @Vérace:所有 DBMS 都支持标准的 `&lt;&gt;`(甚至 MySQL 和 SQL Server)。然而,基本上所有的 DBMS _also_ 都支持非标准的 `!=` (3认同)

a_h*_*ame 12

我喜欢用num_nonnulls这个:

alter table the_table
  add constraint check_at_least_one_email
  check (num_nonnulls(email, p2pmail) > 0);
Run Code Online (Sandbox Code Playgroud)

我更喜欢这个,因为它可以很容易地扩展到多列。

如果您还想处理空字符串:

alter table the_table
  add constraint check_at_least_one_email
  check (num_nonnulls(nullif(trim(email),''), nullif(trim(p2pmail),'')) > 0);
Run Code Online (Sandbox Code Playgroud)

如果您只需要将一个非空值更改> 0= 1