知识库✳

教程与手册

全部教程
  1. 01Oracle 函数手册
  2. 02性能优化手册
  3. 03Linux Shell
  4. 04Oracle 学习与演练
  5. 05网络基础学习
  6. 06数据治理与管理
返回个人网站
甲Oracle 学习教程从 SQL 到 PL/SQL 与运维
首页课程目录搜索演练场
知识库

已完成 0 / 22 章

模块一 · 入门与准备

  • 01Oracle 数据库体系结构
  • 02环境安装与连接方式
  • 03SQL*Plus 与常用工具

模块二 · SQL 查询基础

  • 04SELECT 查询基础
  • 05过滤与排序
  • 06单行函数
  • 07多表连接
  • 08分组聚合与 HAVING
  • 09子查询

模块三 · 数据与对象

  • 10DML 与事务控制
  • 11表与数据类型
  • 12约束
  • 13索引与执行计划
  • 14视图、序列与同义词

模块四 · PL/SQL 编程

  • 15PL/SQL 块与变量
  • 16流程控制与游标
  • 17存储过程与函数
  • 18触发器
  • 19异常处理

模块五 · 运维与进阶

  • 20用户与权限管理
  • 21表空间与存储管理
  • 22备份与恢复
❖

Oracle 学习教程

返回个人网站知识库

示例代码基于 Oracle AI Database 26ai / 23ai,查询示例使用官方 HR 示例方案。

以 Next.js 16 · Tailwind CSS v4 · HeroUI v3 装帧

12
  1. 首页
  2. 课程目录
  3. 约束

第 12 章◆进阶◆建议 45 分钟◆模块三 · 数据与对象

约束

用主键、外键、唯一、检查约束把业务规则固化到数据库层,让脏数据进不来。

学完这一章,你应该能

  • 掌握五类约束的定义与用途
  • 会配置外键的级联行为
  • 能启用、禁用、校验已有数据的约束
  • 知道约束与索引的关系

12.1五类约束

  • NOT NULL:最基础,列级约束,不能命名为表级约束
  • PRIMARY KEY:唯一 + 非空,自动创建唯一索引,一张表只能有一个
  • UNIQUE:允许 NULL(且多个 NULL 互不冲突),也自动建唯一索引
  • FOREIGN KEY:引用父表主键或唯一键,保证引用完整性
  • CHECK:布尔表达式,NULL 会使检查通过(这一点常被忽略)
完整示例
CREATE TABLE project (
  project_id    NUMBER(6),
  project_name  VARCHAR2(50),
  dept_id       NUMBER(4),
  status        VARCHAR2(10),
  budget        NUMBER(12,2),
  start_date    DATE,
  CONSTRAINT pk_project        PRIMARY KEY (project_id),
  CONSTRAINT uk_project_name   UNIQUE (project_name),
  CONSTRAINT ck_project_status CHECK (status IN ('PLAN', 'ACTIVE', 'DONE')),
  CONSTRAINT ck_project_budget CHECK (budget >= 0),
  CONSTRAINT fk_project_dept   FOREIGN KEY (dept_id)
             REFERENCES departments (department_id)
             ON DELETE SET NULL
);

只作示例阅读:5 行写入限制下只开放单独创建普通空表;CTAS、删表、清空表、改结构、触发器和存储程序不允许执行。请在独立学习数据库中练习。

12.2外键的级联行为

三种删除策略
-- 建表时 project.dept_id 上已经有一个外键 fk_project_dept。
-- 同一个列不能同时挂两个指向同一父表的外键(会报 ORA-02275),
-- 所以先把它删掉,再演示不同的删除策略。
ALTER TABLE project DROP CONSTRAINT fk_project_dept;

-- 1) 默认:父表有子记录时禁止删除
ALTER TABLE project ADD CONSTRAINT fk_dept
  FOREIGN KEY (dept_id) REFERENCES departments (department_id);

-- 下面两种是替代方案。同名约束不能重复添加,
-- 想换成哪种就先删掉上面的约束再重建:
--
-- 2) 级联删除:删父表同时删掉子表记录
-- ALTER TABLE project DROP CONSTRAINT fk_dept;
-- ALTER TABLE project ADD CONSTRAINT fk_dept
--   FOREIGN KEY (dept_id) REFERENCES departments (department_id)
--   ON DELETE CASCADE;
--
-- 3) 置空:删父表把子表外键列设为 NULL
-- ALTER TABLE project DROP CONSTRAINT fk_dept;
-- ALTER TABLE project ADD CONSTRAINT fk_dept
--   FOREIGN KEY (dept_id) REFERENCES departments (department_id)
--   ON DELETE SET NULL;

只作示例阅读:5 行写入限制下只开放单独创建普通空表;CTAS、删表、清空表、改结构、触发器和存储程序不允许执行。请在独立学习数据库中练习。

提示 ON DELETE CASCADE 很方便也很危险,一次误删父表记录可能带走大量子数据。生产环境建议优先用「禁止删除」加业务层校验。

12.3启用、禁用与延迟校验

  • 约束类型代码:P 主键、U 唯一、R 外键、C 检查、V 带 WITH CHECK OPTION 的视图、O 只读视图(19c 起另有 H、F、S)。注意:没有 N 这个类型,NOT NULL 是以 C(检查约束)形式存储的
  • 禁用主键约束会连带影响引用它的外键
  • 给大表加约束时,先清理脏数据,再用 NOVALIDATE 快速启用,最后单独 VALIDATE
约束管理
-- 禁用/启用(ENABLE NOVALIDATE 只对新增数据生效,不校验存量)
ALTER TABLE project DISABLE CONSTRAINT ck_project_status;
ALTER TABLE project ENABLE  CONSTRAINT ck_project_status;

-- 启用但不校验历史数据(不锁表,快速上线)
ALTER TABLE project ENABLE NOVALIDATE CONSTRAINT ck_project_status;

-- 延迟约束:事务提交时才检查,便于中间状态违反约束
-- 同名约束已存在,先删再建
ALTER TABLE project DROP CONSTRAINT fk_dept;
ALTER TABLE project ADD CONSTRAINT fk_dept
  FOREIGN KEY (dept_id) REFERENCES departments (department_id)
  DEFERRABLE INITIALLY DEFERRED;

只作示例阅读:5 行写入限制下只开放单独创建普通空表;CTAS、删表、清空表、改结构、触发器和存储程序不允许执行。请在独立学习数据库中练习。

查询约束与违反约束的列
SELECT c.constraint_name,
       c.constraint_type,     -- P/U/R/C
       c.status,
       c.validated,
       cc.column_name,
       c.r_constraint_name    -- 外键指向的父约束
FROM   user_constraints c
LEFT   JOIN user_cons_columns cc
       ON cc.constraint_name = c.constraint_name
WHERE  c.table_name = 'PROJECT'
ORDER  BY c.constraint_type, c.constraint_name;
在你的专用沙箱里执行打开演练场

练习

3 题 · 先自己写,再展开对照

参考答案

ON DELETE CASCADE:删除父表记录时,自动删掉所有引用它的子表记录。
适合子记录离开父记录毫无意义的场景,比如订单明细。

ON DELETE SET NULL:删除父表记录时,把子表的外键列置为 NULL。
适合子记录可以独立存在、只是暂时不归属某父记录的场景。
要求该外键列允许 NULL。

默认(不加任何选项):父表还有子记录时禁止删除,最安全。

自评要点

  • 说清两种行为
  • 指出 CASCADE 的风险:一次误删会带走大量数据

参考答案

先用 ENABLE NOVALIDATE 启用约束,它只对新增和修改的数据生效,
不校验存量数据,因此不需要长时间锁表:

ALTER TABLE big_table
  ENABLE NOVALIDATE CONSTRAINT ck_xxx;

之后在业务低峰期,再单独校验存量数据:

ALTER TABLE big_table VALIDATE CONSTRAINT ck_xxx;

注意 ENABLE NOVALIDATE 会允许已有脏数据继续存在,
所以前置条件是你确认过存量数据本来就合规。

自评要点

  • 知道 ENABLE NOVALIDATE 只作用于新数据
  • 知道之后要补 VALIDATE

参考答案

SELECT c.constraint_name,
       c.constraint_type,   -- P/U/R/C/V/O
       c.status,
       c.validated,
       cc.column_name,
       c.r_constraint_name  -- 外键指向的父约束
FROM   user_constraints c
LEFT   JOIN user_cons_columns cc
       ON cc.constraint_name = c.constraint_name
WHERE  c.table_name = 'EMPLOYEES'
ORDER  BY c.constraint_type, c.constraint_name;
在你的专用沙箱里执行打开演练场

自评要点

  • 知道要关联 USER_CONSTRAINTS 与 USER_CONS_COLUMNS
  • 知道没有 N 类型——NOT NULL 是以 C 存储的
← 上一章

表与数据类型

下一章 →

索引与执行计划