模块课程(2/4)
多重约束和表级约束
确保数据库中的数据在最基本的层(“数据完整性”)正确是根本。如果您只将安全性写入 Node.js 应用程序,则错误可能会导致数据库中的数据不一致。 DDL 级别的约束是最后一道坚不可摧的防线。
主要限制因素
除了PRIMARY KEY(使列唯一且NOT NULL)和经典的NOT NULL和UNIQUE之外,数据的逻辑一致性还有两个基本类别:
1.外键(引用完整性)
REFERENCES 约束确保链接 ID 确实存在于它指向的“父”表中。
例如,订单必须链接到现有客户。
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INTEGER REFERENCES customers(id)
);外键有什么作用?
- 它会阻止您插入
customers中不存在的customer_id。 - 如果有订单指向客户,它会阻止您从
customersDELETE(删除)客户(它可以防止“孤立”记录)。
我们还可以决定当“父”被删除时会发生什么:
customer_id INTEGER REFERENCES customers(id) ON DELETE CASCADE使用 ON DELETE CASCADE,如果我们删除客户,Postgres 将自动删除所有链接的 orders! (请谨慎使用;通常最好使用阻止操作的默认设置。)
2. 检查约束
CHECK 约束在继续保存之前通过测试布尔表达式来验证行。
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'违反”,这对于调试来说更加清晰!
CREATE TABLE prodotti (
id SERIAL PRIMARY KEY,
nome VARCHAR(50),
CONSTRAINT nome_univoco UNIQUE(nome)
);尝试一下
创建一个带有 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 次尝试后可用的解决方案
自定义逻辑的约束
创建一个带有 id (SERIAL PRIMARY KEY)、posti_totali (INTEGER) 和 biglietti_venduti (INTEGER) 的“eventi”表。添加名为“check_capienza”的表约束,其中 biglietti_venduti 不得大于 posti_totali。
显示提示
使用 CONSTRAINT check_capienza CHECK ( expression ) 在底部添加约束
3 次尝试后可用的解决方案