PostgreSQL 教程: NOT NULL 约束

九月 13, 2023

摘要:在本教程中,您将了解 PostgreSQL 非空约束以确保列的值不为空。

NULL 简介

在数据库理论中,NULL 代表未知或信息缺失。NULL 与空字符串或数字零不同。

假设您需要将联系人的电子邮件地址插入表中。您可以索取他或她的电子邮件地址。但是,如果您不知道联系人是否有电子邮件地址,则可以在电子邮件地址列中插入 NULL。在这种情况下,NULL 表示在记录时电子邮件地址未知。

NULL 很特别。它不等于任何东西,甚至不等于它本身。表达式NULL = NULL返回 NULL,因为两个未知值不应该相等是有道理的。

要检查值是否为 NULL,可以使用IS NULL布尔运算符。例如,如果电子邮件地址中的值为 NULL,则以下表达式返回 true。

email_address IS NULL

IS NOT NULL运算符对IS NULL运算符的结果求反。

PostgreSQL NOT NULL 约束

要控制列是否可以接受 NULL,可以使用NOT NULL约束:

CREATE TABLE table_name(
   ...
   column_name data_type NOT NULL,
   ...
);

如果列有NOT NULL约束,则任何在该列中插入更新 NULL 的尝试都将导致错误。

声明 NOT NULL 列

下面的CREATE TABLE语句创建一个带有非空约束名为invoices的新表。

CREATE TABLE invoices(
  id SERIAL PRIMARY KEY,
  product_id INT NOT NULL,
  qty numeric NOT NULL CHECK(qty > 0),
  net_price numeric CHECK(net_price > 0) 
);

此示例通过在product_idqty列的数据类型后面跟上NOT NULL关键字,来声明NOT NULL约束。

请注意,一列可以有多个约束,例如NOT NULLCHECKUNIQUEFOREIGN KEY 彼此相邻。约束的顺序并不重要。PostgreSQL 可以按任意顺序检查列表中的约束。

如果您使用NULL而不是NOT NULL,则该列将接受NULL和非 NULL 值。如果您没有明确指定NULLNOT NULL,它将默认接受NULL

向现有列添加 NOT NULL 约束

要将NOT NULL约束添加到现有表的列,请使用以下形式的ALTER TABLE语句:

ALTER TABLE table_name
  ALTER COLUMN column_name SET NOT NULL;

要给多个列添加 NOT NULL 约束,请使用以下语法:

ALTER TABLE table_name
  ALTER COLUMN column_name_1 SET NOT NULL,
  ALTER COLUMN column_name_2 SET NOT NULL,
  ...;

让我们看一下下面的例子。

首先,创建一个新表,名为生产订单 ( production_orders):

CREATE TABLE production_orders (
	id SERIAL PRIMARY KEY,
	description VARCHAR (40) NOT NULL,
	material_id VARCHAR (16),
	qty NUMERIC,
	start_date DATE,
	finish_date DATE
);

接下来,在production_orders表中插入一个新行:

INSERT INTO production_orders (description)
VALUES('Make for Infosys inc.');

然后,为了确保qty字段不为空,您可以给qty列添加非空约束。但是,该列已包含数据。如果您尝试添加非空约束,PostgreSQL 将发出错误。

要将NOT NULL约束添加到已包含 NULL 的列,您需要首先更新NULL为非 NULL,如下所示:

UPDATE production_orders
SET qty = 1;

qty列中的值更新为 1。现在,您可以将NOT NULL约束添加到qty列中:

ALTER TABLE production_orders 
  ALTER COLUMN qty
    SET NOT NULL;

之后,您可以更新material_idstart_datefinish_date列的值,以满足非空约束检查:

UPDATE production_orders
SET material_id = 'ABC',
    start_date = '2015-09-01',
    finish_date = '2015-09-01';

向多列添加非空约束:

ALTER TABLE production_orders 
  ALTER COLUMN material_id SET NOT NULL,
  ALTER COLUMN start_date SET NOT NULL,
  ALTER COLUMN finish_date SET NOT NULL;

最后,尝试将qty列中的值更新为 NULL:

UPDATE production_orders
SET qty = NULL;

PostgreSQL 发出错误消息:

ERROR:  null value in column "qty" violates not-null constraint
DETAIL:  Failing row contains (1, make for infosys inc., ABC, null, 2015-09-01, 2015-09-01).

NOT NULL 约束的特殊情况

除了NOT NULL约束之外,您还可以使用 CHECK 约束来强制列接受非 NULL 值。NOT NULL约束等效于以下CHECK约束:

CHECK(column IS NOT NULL)

这很有用,因为有时您可能需要ab其中一个列不为空,而不是同时要求两者都不为空。

例如,您可能希望用户表的usernameemail中任一列不为 NULL 或空字符串。在这种情况下,您可以按如下方式使用CHECK约束:

CREATE TABLE users (
 id serial PRIMARY KEY,
 username VARCHAR (50),
 password VARCHAR (50),
 email VARCHAR (50),
 CONSTRAINT username_email_notnull CHECK (
   NOT (
     ( username IS NULL  OR  username = '' )
     AND
     ( email IS NULL  OR  email = '' )
   )
 )
);

以下语句有效。

INSERT INTO users (username, email)
VALUES
	('user1', NULL),
	(NULL, 'email1@example.com'),
	('user2', 'email2@example.com'),
	('user3', '');

但是,以下语句将执行失败,因为它违反了CHECK约束:

INSERT INTO users (username, email)
VALUES
	(NULL, NULL),
	(NULL, ''),
	('', NULL),
	('', '');
ERROR:  new row for relation "users" violates check constraint "username_email_notnull"

概括

  • 对列使用NOT NULL约束来强制列不接受NULL。默认情况下,列可以保存 NULL。

  • 要检查某个值是否存在NULL,可以使用IS NULL运算符。IS NOT NULLIS NULL取反的结果。

  • 切勿使用等于运算符=来比较NULL值,因为它总是返回NULL