跳转到主要内容
模块 9 · 第 2 课(共 4)课程中的34/57~12 min
模块课程(2/4)

多重约束和表级约束

确保数据库中的数据在最基本的层(“数据完整性”)正确是根本。如果您只将安全性写入 Node.js 应用程序,则错误可能会导致数据库中的数据不一致。 DDL 级别的约束是最后一道坚不可摧的防线。

主要限制因素

除了PRIMARY KEY(使列唯一且NOT NULL)和经典的NOT NULL和UNIQUE之外,数据的逻辑一致性还有两个基本类别:

1.外键(引用完整性)

REFERENCES 约束确保链接 ID 确实存在于它指向的“父”表中。 例如,订单必须链接到现有客户。

SQL
CREATE TABLE orders (
  id SERIAL PRIMARY KEY,
  customer_id INTEGER REFERENCES customers(id)
);

外键有什么作用?

  • 它会阻止您插入 customers 中不存在的 customer_id。
  • 如果有订单指向客户,它会阻止您从 customers DELETE (删除)客户(它可以防止“孤立”记录)。

我们还可以决定当“父”被删除时会发生什么:

SQL
customer_id INTEGER REFERENCES customers(id) ON DELETE CASCADE

使用 ON DELETE CASCADE,如果我们删除客户,Postgres 将自动删除所有链接的 orders! (请谨慎使用;通常最好使用阻止操作的默认设置。)

2. 检查约束

CHECK 约束在继续保存之前通过测试布尔表达式来验证行。

SQL
CREATE TABLE contratti (
  id SERIAL PRIMARY KEY,
  stipendio NUMERIC(10,2) CHECK (stipendio > 0),
  data_inizio DATE,
  data_fine DATE,
  CHECK (data_fine > data_inizio)
);

第一个 CHECK 是一个列约束(它仅引用 stipendio)。 底部的第二个 CHECK 是一个表约束(它可以跨越多个列的值,并且必须在底部声明)。

如果 INSERT 或 UPDATE 尝试在开始之前保存结束,Postgres 将拒绝它并出现错误!

命名限制

为约束指定一个显式名称(使用 CONSTRAINT 关键字)通常是一种很好的做法。这样,当 Postgres 阻塞一条记录时,错误会告诉你例如“constraint 'stipendio_positivo'违反”,这对于调试来说更加清晰!

SQL
CREATE TABLE prodotti (
  id SERIAL PRIMARY KEY,
  nome VARCHAR(50),
  CONSTRAINT nome_univoco UNIQUE(nome)
);

尝试一下

锻炼#sql.m9.l2.e1
尝试:0加载中...

创建一个带有 id(串行主键)和“customer_id”(整数)的“prenotazioni”表。使用 CONSTRAINT fk_cliente FOREIGN KEY (customer_id) REFERENCEScustomers(id) 为外键约束指定显式名称。在底部执行此操作,作为表约束。

正在加载编辑器...
显示提示

写入 CONSTRAINT fk_cliente FOREIGN KEY (local_column) REFERENCES external_table(external_col)

3 次尝试后可用的解决方案

自定义逻辑的约束

锻炼#sql.m9.l2.e2
尝试:0加载中...

创建一个带有 id (SERIAL PRIMARY KEY)、posti_totali (INTEGER) 和 biglietti_venduti (INTEGER) 的“eventi”表。添加名为“check_capienza”的表约束,其中 biglietti_venduti 不得大于 posti_totali。

正在加载编辑器...
显示提示

使用 CONSTRAINT check_capienza CHECK ( expression ) 在底部添加约束

3 次尝试后可用的解决方案