MySQL 约束

核心目标: 学习如何使用约束来强制执行 MySQL 表中数据的完整性和规则,确保数据的准确性、一致性和可靠性。

什么是约束?
约束是在表的数据列上强制执行的规则。它们用于限制可以插入、更新或删除到表中的数据类型或值。如果任何操作违反了约束规则,该操作将被中止。

约束的类型:

1. NOT NULL (非空约束)

作用:确保列不能存储 NULL 值。如果尝试插入或更新为 NULL,操作将失败。
语法 (建表时):

column_name data_type NOT NULL

语法 (修改表 - 添加):

ALTER TABLE table_name MODIFY COLUMN column_name data_type NOT NULL;

语法 (修改表 - 移除,允许 NULL):

ALTER TABLE table_name MODIFY COLUMN column_name data_type NULL; -- 或省略 NULL 关键字

示例:

-- 创建表时指定 email 不能为空
CREATE TABLE users (
id INT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
email VARCHAR(100) NOT NULL
);

-- 修改现有表的 age 列,使其不能为空
ALTER TABLE users MODIFY COLUMN age INT NOT NULL;
2. UNIQUE (唯一约束)

作用:保证列(或列组合)中的所有值都是唯一的。允许存在一个 NULL 值(除非该列也被定义为 NOT NULL)。
语法 (建表时 - 列级):

column_name data_type UNIQUE

语法 (建表时 - 表级,可用于多列):

CONSTRAINT constraint_name UNIQUE (column1, column2, ...)

语法 (修改表 - 添加):

ALTER TABLE table_name ADD CONSTRAINT constraint_name UNIQUE (column_name);

语法 (修改表 - 删除):

ALTER TABLE table_name DROP INDEX constraint_name; -- 唯一约束通常通过唯一索引实现
-- 或 ALTER TABLE table_name DROP CONSTRAINT constraint_name; (如果定义时使用了 CONSTRAINT 关键字)

示例:

-- 创建表时指定 email 唯一
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(100),
email VARCHAR(100) UNIQUE
);

-- 创建表时指定用户名和部门 ID 组合唯一
CREATE TABLE memberships (
membership_id INT PRIMARY KEY,
user_id INT,
group_id INT,
CONSTRAINT uq_user_group UNIQUE (user_id, group_id)
);

-- 给 products 表的 product_code 添加唯一约束
ALTER TABLE products ADD CONSTRAINT uq_product_code UNIQUE (product_code);
3. PRIMARY KEY (主键约束)

作用:唯一标识表中的每一行。它隐含了 NOT NULLUNIQUE 约束。一个表只能有一个主键(可以是单列或多列组合)。主键列的值不能被修改,也不能为 NULL
语法 (建表时 - 列级):

column_name data_type PRIMARY KEY

语法 (建表时 - 表级,用于单列或复合主键):

CONSTRAINT constraint_name PRIMARY KEY (column1, column2, ...)

语法 (修改表 - 添加):

ALTER TABLE table_name ADD CONSTRAINT constraint_name PRIMARY KEY (column_name);

语法 (修改表 - 删除):

ALTER TABLE table_name DROP PRIMARY KEY; -- 无需指定名称,因为只有一个

示例:

-- 创建表时将 id 设为主键
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
order_date DATE
);

-- 创建表时将 user_id 和 role_id 设为复合主键
CREATE TABLE user_roles (
user_id INT,
role_id INT,
PRIMARY KEY (user_id, role_id)
);

-- 为已存在的表 students 添加主键
-- ALTER TABLE students ADD PRIMARY KEY (student_id);
4. AUTO_INCREMENT (自增属性)

作用:这不是严格意义上的约束,但常与 PRIMARY KEY 一起用于整数列。当插入新行时,如果未指定该列的值,MySQL 会自动为其生成一个比当前最大值大 1 的唯一序列号。
语法 (建表时):

column_name INT AUTO_INCREMENT PRIMARY KEY

注意:

  • 一个表只能有一个 AUTO_INCREMENT 列。
  • 该列必须是键(通常是主键或唯一键)。
  • 默认从 1 开始,每次递增 1。

示例:

CREATE TABLE logs (
log_id INT AUTO_INCREMENT PRIMARY KEY,
log_message TEXT,
log_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

5. FOREIGN KEY (外键约束)
作用:用于在两个表之间建立连接并强制引用完整性。它确保子表(包含外键的表)中的外键列的值必须在父表(被引用的表)的某个主键或唯一键列中存在,或者该外键列的值为 NULL(如果该列允许 NULL)。
语法 (建表时 - 表级):

CONSTRAINT constraint_name
FOREIGN KEY (child_column1, ...)
REFERENCES parent_table(parent_column1, ...)
[ON DELETE action]
[ON UPDATE action]

语法 (修改表 - 添加):

ALTER TABLE child_table
ADD CONSTRAINT constraint_name
FOREIGN KEY (child_column)
REFERENCES parent_table(parent_column)
[ON DELETE action]
[ON UPDATE action];

语法 (修改表 - 删除):

ALTER TABLE child_table DROP FOREIGN KEY constraint_name;

ON DELETE / ON UPDATE 动作 (指定当父表记录被删除/更新时,子表如何响应):

  • RESTRICT (默认): 如果子表存在相关记录,则阻止删除/更新父表记录。
  • CASCADE: 父表记录删除/更新时,自动删除/更新子表中相关的记录。(级联删除需谨慎!)
  • SET NULL: 父表记录删除/更新时,将子表中相应的外键列设置为 NULL。(前提是子表外键列允许 NULL)。
  • NO ACTION: 同 RESTRICT (标准 SQL 的概念,MySQL 中行为类似)。
  • SET DEFAULT: 父表记录删除/更新时,将子表中相应的外键列设置为其默认值。(不常用,有引擎/版本限制)。

示例:

-- 创建 orders 表,其中 customer_id 是外键,引用 customers 表的 id
CREATE TABLE customers (
id INT PRIMARY KEY,
name VARCHAR(100)
);

CREATE TABLE orders (
order_id INT PRIMARY KEY,
order_number VARCHAR(20),
customer_id INT, -- 外键列
order_date DATE,
CONSTRAINT fk_customer
FOREIGN KEY (customer_id) REFERENCES customers(id)
ON DELETE SET NULL -- 如果客户被删除,订单的 customer_id 设为 NULL
ON UPDATE CASCADE -- 如果客户 ID 更新,订单的 customer_id 也更新
);

-- 为已存在的 enrollments 表添加外键到 students 表
-- ALTER TABLE enrollments
-- ADD CONSTRAINT fk_student_enrollment
-- FOREIGN KEY (student_id) REFERENCES students(student_id)
-- ON DELETE RESTRICT; -- 不允许删除有选课记录的学生
6. DEFAULT (默认值约束)

作用:如果插入新行时没有为某个列指定值,则该列会自动填充指定的默认值。
语法 (建表时):

column_name data_type DEFAULT default_value

语法 (修改表 - 添加/修改):

ALTER TABLE table_name ALTER COLUMN column_name SET DEFAULT default_value;

语法 (修改表 - 删除):

ALTER TABLE table_name ALTER COLUMN column_name DROP DEFAULT;

示例:

-- 创建表时设置注册日期默认为当前日期,状态默认为 'active'
CREATE TABLE accounts (
user_id INT PRIMARY KEY,
username VARCHAR(50),
registration_date DATE DEFAULT (CURDATE()), -- MySQL 8.0.13+ 支持表达式默认值
status VARCHAR(10) DEFAULT 'active'
);

-- 给 products 表的 'is_available' 列设置默认值为 1
ALTER TABLE products ALTER COLUMN is_available SET DEFAULT 1;
7. CHECK (检查约束)

作用:定义一个布尔表达式,用于验证插入或更新到列中的数据。只有当表达式结果为 TRUE 或 UNKNOWN (由于 NULL) 时,操作才被允许。(MySQL 8.0.16+ 才真正强制执行)
语法 (建表时 - 列级):

column_name data_type CHECK (condition)

语法 (建表时 - 表级):

CONSTRAINT constraint_name CHECK (condition)

语法 (修改表 - 添加):

ALTER TABLE table_name ADD CONSTRAINT constraint_name CHECK (condition);

语法 (修改表 - 删除):

ALTER TABLE table_name DROP CHECK constraint_name;

示例:

-- 创建表时确保价格大于 0
CREATE TABLE products (
product_id INT PRIMARY KEY,
name VARCHAR(100),
price DECIMAL(10, 2) CHECK (price > 0),
stock INT CHECK (stock >= 0)
);

-- 添加约束确保折扣在 0 到 1 之间
ALTER TABLE promotions ADD CONSTRAINT chk_discount CHECK (discount >= 0 AND discount <= 1);

练习题 (Practice Exercises - Constraints with Answers)
  1. 创建一个名为 departments 的表,包含 dept_id (INT, 主键, 自增) 和 dept_name (VARCHAR(50), 不能为空, 且唯一)。
    答案:

    CREATE TABLE departments (
    dept_id INT AUTO_INCREMENT PRIMARY KEY,
    dept_name VARCHAR(50) NOT NULL UNIQUE
    );
    
  2. 创建一个名为 employees 的表,包含 emp_id (INT, 主键), emp_name (VARCHAR(100), 不能为空), salary (DECIMAL(10, 2), 必须大于 0), dept_id (INT), 并添加一个外键约束 fk_emp_dept,将 dept_id 关联到 departments 表的 dept_id 列,当部门被删除时,员工的 dept_id 设为 NULL。
    答案:

    CREATE TABLE employees (
    emp_id INT PRIMARY KEY,
    emp_name VARCHAR(100) NOT NULL,
    salary DECIMAL(10, 2) CHECK (salary > 0),
    dept_id INT,
    CONSTRAINT fk_emp_dept
    FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
    ON DELETE SET NULL
    );
    
  3. 修改 employees 表,为 salary 列添加一个默认值 3000.00。
    答案:

    ALTER TABLE employees ALTER COLUMN salary SET DEFAULT 3000.00;
    
  4. 假设 employees 表已存在,并且没有唯一约束。请为 emp_email 列(VARCHAR(100))添加一个唯一约束,约束名为 uq_emp_email
    答案:

    -- 首先确保 emp_email 列存在
    -- ALTER TABLE employees ADD COLUMN emp_email VARCHAR(100);
    -- 然后添加唯一约束
    ALTER TABLE employees ADD CONSTRAINT uq_emp_email UNIQUE (emp_email);
    
  5. 删除 employees 表的外键约束 fk_emp_dept
    答案:

    ALTER TABLE employees DROP FOREIGN KEY fk_emp_dept;
    -- 如果不确定约束名,可以先用 SHOW CREATE TABLE employees; 查看
    

你可能感兴趣的:(SQL教程,mysql,sql,数据库)