创建和管理检查限制条件

借助 CHECK 限制条件,您可以指定一个或多个列的值必须满足布尔值表达式。在本文中,我们将介绍如何在数据库中管理此类限制条件。

向新表添加检查限制条件

在以下 CREATE TABLE 代码段中,我们创建了一个表来存储有关音乐会的信息。为了使音乐会的结束时间晚于开始时间,我们添加了检查限制条件。

GoogleSQL

CREATE TABLE Concerts (
  ConcertId INT64,
  StartTime Timestamp,
  EndTime Timestamp,
  CONSTRAINT start_before_end CHECK(StartTime < EndTime),
) PRIMARY KEY (ConcertId);

PostgreSQL

CREATE TABLE Concerts (
  ConcertId BIGINT,
  StartTime TIMESTAMPTZ,
  EndTime TIMESTAMPTZ,
  CONSTRAINT start_before_end CHECK(StartTime < EndTime),
  PRIMARY KEY (ConcertId)
);

限制条件的定义从 CONSTRAINT 关键字开始。在此示例中,我们将该限制条件明确命名为 start_before_end,因此可以在错误消息中以及在需要引用它时很容易识别它。如果未指定名称,则 Spanner 会提供名称,并且生成的名称以前缀 CK_ 开头。限制条件名称的范围限定为架构以及表和索引的名称,并且在架构内必须具有唯一性。检查限制条件定义包括关键字 CHECK 和括号中的表达式。表达式只能引用此表的列。在此示例中,它引用了 StartTimeEndTime,因此在这里进行检查可确保音乐会的开始时间始终小于结束时间。

插入新行或更新现有行的 StartTimeEndTime 时,会计算检查限制条件表达式的值。如果表达式的计算结果为 TRUENULL,则检查限制条件会允许更改数据。如果表达式的计算结果为 FALSE,则不允许更改数据。

  • 以下限制适用于检查限制条件 expression 术语。

    • 表达式只能引用同一表中的列。

    • 表达式必须直接引用至少一个非生成的列,无论是直接引用,还是通过引用非生成的列的生成的列进行引用。

    • 表达式无法引用已设置 allow_commit_timestamp 选项的列。

    • 表达式不能包含子查询

    • 表达式不能包含非确定性函数,例如 CURRENT_DATE()CURRENT_TIMESTAMP()

向现有表添加检查限制条件

使用以下 ALTER TABLE 语句,我们添加了一个约束条件,以确保所有音乐会 ID 均大于零。

ALTER TABLE Concerts
ADD CONSTRAINT concert_id_gt_0 CHECK (ConcertId > 0);

同样,我们已将该限制条件命名为 concert_id_gt_0。向现有表添加 CHECK 限制条件会立即开始对新数据强制执行该限制条件,并启动长时间运行的操作以验证现有数据是否符合新的限制条件。由于此验证是以长时间运行的操作执行的,因此对表持续进行的事务不会受到影响。如需了解详情,请参阅架构更新性能。如果现有数据存在任何违规情况,则会回滚该限制条件。

移除检查限制条件

以下 DDL 语句删除 Concerts 表中的 CHECK 限制条件。

ALTER TABLE Concerts
DROP CONSTRAINT concert_id_gt_0;

修改检查约束表达式

不允许修改 CHECK 限制条件的表达式,而是需要删除现有限制条件,并使用新表达式创建新限制条件。

查看检查约束的属性

Spanner 的 INFORMATION_SCHEMA 包含有关数据库检查限制条件的信息。以下示例介绍了您可以通过查询信息架构回答的一些问题。

我的数据库中定义了哪些检查限制条件?

SELECT tc.CONSTRAINT_NAME, tc.TABLE_NAME, tc.CONSTRAINT_TYPE
FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS as tc
WHERE tc.CONSTRAINT_TYPE = 'CHECK';

数据库中的检查限制条件的当前状态如何?

如果向现有表添加了检查限制条件,则您可能需要查看当前状态,以确定(例如)是否已通过现有数据验证了所有现有数据。如果 SPANNER_STATE 在以下查询中返回 VALIDATING_DATA,则表示 Spanner 仍在根据该限制条件验证现有数据。

SELECT cc.CONSTRAINT_NAME, cc.SPANNER_STATE
FROM INFORMATION_SCHEMA.CHECK_CONSTRAINTS as cc;

后续步骤