SQL 外键约束

摘要:在本教程中,您将学习 SQL 外键以及如何使用 FOREIGN KEY 约束来定义外键。

SQL 外键简介 #

在 SQL 中,外键是一个表中的一个或一组列,它引用另一个表的主键

  • 包含外键的表称为子表外键表,或引用表
  • 其主键列被外键引用的表称为父表被引用表

外键的主要目的是建立子表和父表之间的关系。

例如,对于子表中外键的某个值,您总能在父表的主键中找到相应的值。

假设我们有两个表:projectsproject_milestones

  • project_milestones 表有一个外键 project_id,它引用 projects 表中的 project_id
  • project_milestones 表称为子表外键表,而 projects 表是父表被引用表

对于 project_milestones 表中的每一行,您都可以在 projects 表中找到 project_id 的值。这个规则被称为两个表之间的引用完整性约束

一个表可以有多个外键,但只能有一个主键。

在 SQL 中,您使用外键约束来创建外键。

SQL 外键约束 #

以下是在子表中定义外键约束的语法:

CONSTRAINT constraint_name
FOREIGN KEY (column1, column2)
REFERENCES parent_table(column1, column2)
ON DELETE delete_action
ON UPDATE update_action;Code language: SQL (Structured Query Language) (sql)

在此语法中:

  • 首先,在 CONSTRAINT 子句中指定外键的约束名称。如果您不为外键命名,大多数数据库系统会自动分配一个名称。
  • 其次,提供一个或多个要包含在外键中的列。
  • 第三,指定父表(被引用表)及其一个或多个列。
  • 最后,定义当父表主键中的值被更新或删除时的操作。

定义外键约束示例 #

第 1 步:创建一个新表,名为 projects,用于存储项目数据。

CREATE TABLE projects (
    project_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
    project_name VARCHAR(255) NOT NULL,
    start_date DATE NOT NULL,
    end_date DATE NOT NULL
);Code language: SQL (Structured Query Language) (sql)

试一试

第 2 步:创建一个新表,名为 project_milestones,用于存储项目里程碑。

CREATE TABLE project_milestones (
  milestone_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  milestone VARCHAR(255),
  start_date DATE NOT NULL,
  end_date DATE NOT NULL,
  project_id INT NOT NULL,
  FOREIGN KEY (project_id) REFERENCES projects (project_id)
);Code language: SQL (Structured Query Language) (sql)

试一试

project_milestones 表中,我们定义了一个包含 project_id 的外键约束,并将其引用到 projects 表的 project_id 列。

由于我们没有明确指定外键约束的名称,数据库系统会自动生成一个名为 project_milestones_project_id_fkey 的名称。

请注意,生成的名称可能因数据库系统而异。

使用外键约束插入数据 #

第 1 步:projects 表中插入一个新行。

INSERT INTO
  projects (project_name, start_date, end_date)
VALUES
  ('Super App', '2025-01-01', '2025-12-31');Code language: SQL (Structured Query Language) (sql)

试一试

第 2 步:尝试向 project_milestones 表中插入一个新行,其 project_id 值在 projects 表中不存在。

INSERT INTO
  project_milestones (milestone, start_date, end_date, project_id)
VALUES
  ('Initiation', '2025-01-01', '2025-01-31', 0);Code language: SQL (Structured Query Language) (sql)

试一试

数据库系统将发出类似这样的错误消息:

ERROR:  insert or update on table "project_milestones" violates foreign key constraint "project_milestones_project_id_fkey"
DETAIL:  Key (project_id)=(0) is not present in table "projects".Code language: SQL (Structured Query Language) (sql)

该错误消息指出 project_id 为 0 的值在 projects 表中不存在。

第 3 步:向 project_milestones 表中插入一个具有有效 project_id 值的新行。

INSERT INTO
  project_milestones (milestone, start_date, end_date, project_id)
VALUES
  ('Initiation', '2025-01-01', '2025-01-31', 1);Code language: SQL (Structured Query Language) (sql)

试一试

向现有表添加 FOREIGN KEY 约束 #

要向表中添加外键约束,您可以使用 ALTER TABLE ... ADD CONSTRAINT 语句。

ALTER TABLE foreign_key_table
ADD CONSTRAINT constraint_name
FOREIGN KEY (column1, column2)
     REFERENCES parent_table(column1, column2)
     ON UPDATE update_action
     ON DELETE delete_action;Code language: SQL (Structured Query Language) (sql)

如果表中已有数据,在向外键表添加外键约束之前,您必须确保数据是有效的。否则,您会遇到约束冲突错误。

第 1 步创建一个名为 project_tasks 的表。

CREATE TABLE project_tasks (
  task_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  title VARCHAR(255) NOT NULL,
  completed BOOL NOT NULL DEFAULT FALSE,
  start_date DATE NOT NULL,
  end_date DATE NOT NULL,
  milestone_id INT
);Code language: SQL (Structured Query Language) (sql)

试一试

第 2 步:向 project_tasks 表添加一个外键约束。

ALTER TABLE project_tasks
ADD CONSTRAINT project_tasks_milestone_id_fkey 
FOREIGN KEY (milestone_id) 
REFERENCES project_milestones (milestone_id);Code language: SQL (Structured Query Language) (sql)

试一试

删除外键约束 #

要删除外键约束,您可以使用 ALTER TABLE 语句。

ALTER TABLE foreign_key_table
DROP CONSTRAINT fk_name;Code language: SQL (Structured Query Language) (sql)

例如,以下语句移除了 project_tasks_milestone_id_fkey 外键约束。

ALTER TABLE project_tasks
DROP CONSTRAINT project_tasks_milestone_id_fkey;Code language: SQL (Structured Query Language) (sql)

试一试

删除操作 #

当您删除父表中的一行时,数据库系统需要决定如何处理子表中的行。

例如,如果您从 projects 表中删除一行,数据库系统必须知道如何处理那些 project_id 与被删除项目相关的行。

默认情况下,如果子表中存在相关行,数据库系统不允许您删除父表中的行。如果您尝试这样做,数据库系统将拒绝删除并发出错误。

SQL 外键的删除操作

  • RESTRICT:当子表中有行引用父表中的值时,您不能删除父表中的该行。
  • SET NULL:当您从父表中删除相关行时,数据库系统会将外键列中的值设置为 NULL
  • SET DEFAULT:当您从父表中删除相关行时,数据库系统会用其默认值更新外键列。
  • CASCADE:当您从父表中删除相关行时,数据库系统会删除子表中的相关行。

更新操作 #

更新操作指示数据库系统在您更新父表中的相关行时如何处理子表中的行。

SQL 为外键定义了以下删除操作:

  • RESTRICT:如果子表中存在依赖行,数据库系统会阻止更新主键。这是默认行为。
  • SET NULL:当您更新父表的主键值时,数据库系统会将相关行的外键列值设置为 NULL
  • SET DEFAULT:当您更新父表的主键值时,数据库系统会将相关行的外键列值设置为其默认值。
  • CASCADE:当您更新父表的主键值时,数据库系统会自动更新外键列中的值。

在实践中,您很少更新主键值。因此,您很少需要 ON UPDATE 操作。

摘要 #

  • 使用 SQL 外键约束来强制执行两个表之间的引用完整性。

测验 #

数据库 #

本教程是否有帮助?
© .