数据库约束

发布于:2025-06-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

       在 SQL Server 中,约束(Constraint) 是用于确保数据库中数据的完整性、一致性和有效性的规则。它们可以防止无效数据进入表中,保证数据质量,让数据库的结构和内容更合理、可靠。以下从常见约束类型、作用、语法和使用场景等方面详细讲解:

一、常见约束类型及详细说明

1. 主键约束(PRIMARY KEY

  • 作用
    • 唯一标识表中的每一行数据,相当于表的 “身份证”。
    • 保证主键列的值不重复不为空(NOT NULL 。
    • 数据库会自动基于主键建立索引,大幅提升查询效率(比如按主键查询某行数据时,能快速定位)。
  • 语法示例
    -- 方式1:创建表时直接定义主键
    CREATE TABLE Student (
        ID INT PRIMARY KEY, -- ID 列设为主键,自动非空、唯一
        Name VARCHAR(50)
    );
    
    -- 方式2:通过 CONSTRAINT 自定义约束名(更灵活,方便管理)
    CREATE TABLE Student (
        ID INT,
        Name VARCHAR(50),
        CONSTRAINT PK_StudentID PRIMARY KEY (ID) -- PK_StudentID 是自定义约束名,PK 是主键缩写
    );
    
  • 特点
    • 一张表只能有 1 个主键(但可以是 “复合主键”,即多个列组合成主键,比如 (ID, ClassID) ,需保证组合值唯一 )。
    • 主键列的数据类型通常选 INTBIGINT 或带唯一性的字符类型(如 CHAR(10) ),方便快速检索。

2. 唯一约束(UNIQUE

  • 作用
    保证某一列或多列的组合值唯一,防止重复数据,但允许列值为空(NULL(不过如果列本身设了 NOT NULL ,就既非空又唯一 )。
    常用于 “辅助唯一标识” 的场景(比如学生表中 “手机号” 列,要求不重复,但不是表的主键 )。
  • 语法示例
    CREATE TABLE Student (
        ID INT PRIMARY KEY,
        Phone VARCHAR(20) UNIQUE, -- 直接定义,自动生成默认约束名
        Email VARCHAR(50),
        CONSTRAINT UQ_StudentEmail UNIQUE (Email) -- 自定义约束名 UQ_StudentEmail,UQ 是唯一约束缩写
    );
    
  • 特点
    • 一张表可以有多个唯一约束(比如同时约束手机号、邮箱等 )。
    • 唯一约束也会隐式创建索引,提升查询唯一性列的效率,但索引类型和主键的索引有区别(主键是聚集索引,唯一约束默认是非聚集索引,可手动调整 )。

3. 外键约束(FOREIGN KEY

  • 作用
    建立表与表之间的 “关联关系”,保证从表(子表)中引用的列值,在主表(父表)中必须存在,维护数据的 “引用完整性”。
    比如:Score 表(子表)的 StudentID 列,必须关联 Student 表(父表)的 ID 列,防止出现 “成绩表引用了不存在的学生 ID” 的情况。
  • 语法示例
    -- 先建主表 Student
    CREATE TABLE Student (
        ID INT PRIMARY KEY,
        Name VARCHAR(50)
    );
    
    -- 再建从表 Score,定义外键关联 Student 表的 ID
    CREATE TABLE Score (
        ScoreID INT PRIMARY KEY,
        StudentID INT,
        Score INT,
        CONSTRAINT FK_Score_StudentID FOREIGN KEY (StudentID) REFERENCES Student(ID)
        -- FK_Score_StudentID 是自定义约束名,FK 是外键缩写;REFERENCES 指定关联的主表和列
    );
    
  • 特点
    • 外键列的数据类型必须和主表关联列一致(比如主表 ID 是 INT ,外键列也得是 INT )。
    • 删除或更新主表数据时,需注意 “级联操作”(可设置 ON DELETE CASCADE 或 ON UPDATE CASCADE ,让从表数据自动同步变更,避免破坏关联 )。

4. 检查约束(CHECK

  • 作用
    自定义规则,限制列值必须满足某个条件,保证数据符合业务逻辑。
    比如:学生成绩必须在 0 - 100 之间,性别只能是  或  等。
  • 语法示例
    CREATE TABLE Student (
        ID INT PRIMARY KEY,
        Name VARCHAR(50),
        Gender CHAR(2),
        Score INT,
        -- 直接定义,检查 Gender 只能是 '男' 或 '女'
        CONSTRAINT CK_Student_Gender CHECK (Gender IN ('男', '女')), 
        -- 自定义约束名 CK_Student_Score,检查 Score 在 0-100 之间
        CONSTRAINT CK_Student_Score CHECK (Score >= 0 AND Score <= 100) 
    );
    
  • 特点
    • 条件可以是简单的逻辑判断(如范围、枚举),也可以是复杂的表达式(但太复杂会影响性能,需谨慎 )。
    • SQL Server 对 CHECK 约束的 “严格性” 有特殊点:默认情况下,CHECK 约束不阻止 NULL 值(除非列本身设了 NOT NULL )。比如列设了 CHECK (Score >= 0) ,但 Score 允许 NULL ,就可以插入 NULL 值。

5. 默认约束(DEFAULT

  • 作用
    给列设置 “默认值”,当插入数据时,如果没显式指定该列的值,数据库自动填入默认值。
    比如:学生表的 “入学时间”,默认填当前系统时间;“状态” 列默认填 正常 。
  • 语法示例
    CREATE TABLE Student (
        ID INT PRIMARY KEY,
        Name VARCHAR(50),
        EnrollDate DATETIME DEFAULT GETDATE(), -- 调用 GETDATE() 函数,默认填当前时间
        Status VARCHAR(10) DEFAULT '正常' -- 默认填 '正常'
    );
    
  • 特点
    • 默认值可以是固定值(如 '正常' ),也可以是函数(如 GETDATE() 获取当前时间 )。
    • 仅在 “插入数据时未显式赋值” 时触发,更新数据时不会自动重置为默认值。

二、约束的创建、修改与删除

1. 创建约束的时机

  • 建表时直接定义:最常见,在 CREATE TABLE 语句里,和列定义写在一起(如前面的示例 )。
  • 建表后添加约束:用 ALTER TABLE 语句,适合表已存在,后续补充约束的场景。
    示例(给已存在的 Student 表加唯一约束):
    ALTER TABLE Student
    ADD CONSTRAINT UQ_Student_Phone UNIQUE (Phone);
    

2. 修改约束

SQL Server 没有直接 “修改约束” 的语法,通常的做法是:

  • 删除旧约束 → 重新创建新约束
    示例(修改 CHECK 约束,把成绩范围从 0-100 改成 0-150 ):
    -- 1. 删除旧约束
    ALTER TABLE Student
    DROP CONSTRAINT CK_Student_Score;
    
    -- 2. 重新创建新约束
    ALTER TABLE Student
    ADD CONSTRAINT CK_Student_Score CHECK (Score >= 0 AND Score <= 150);
    

3. 删除约束

用 ALTER TABLE ... DROP CONSTRAINT ... 语法,指定约束名即可。
示例:

ALTER TABLE Student
DROP CONSTRAINT UQ_Student_Phone; -- 删除唯一约束 UQ_Student_Phone

三、约束的作用与价值

  1. 保证数据完整性
    防止无效数据(如重复学号、负数成绩、不存在的外键关联等 )进入数据库,让数据 “干净、可信”。
  2. 简化业务逻辑
    把数据校验规则交给数据库约束,不用在应用程序里反复判断,减少代码冗余。
  3. 提升查询效率
    主键、唯一约束自动创建的索引,能加速查询,让数据库操作更高效。
  4. 文档化规则
    约束定义清晰记录了数据规则,其他人维护数据库时,能快速理解表的设计意图。

四、约束使用的注意事项

  1. 命名规范
    约束名最好带前缀(如 PK_UQ_FK_CK_ ),方便区分类型,也便于后续管理(比如 PK_StudentID 一看就知道是学生表的主键 )。
  2. 性能平衡
    过多、过复杂的约束(尤其是 CHECK 约束和复合外键 )会增加数据库的计算负担,插入、更新数据时变慢。需在 “数据完整性” 和 “性能” 之间找平衡。
  3. 外键的级联操作
    删除或更新主表数据时,若不设置级联(ON DELETE CASCADE 等 ),可能因外键关联报错。需根据业务需求,决定是否自动同步删除 / 更新从表数据。

五、练习

练习一:基础约束综合题(建表 + 主键 / 唯一 / 检查 / 默认)

题目
创建 Employee 表,包含以下字段和约束:

  • EmpID:整数,主键,自增(从 1 开始,每次 +1)
  • EmpName:长度 50 的字符串,非空,且值唯一
  • Gender:固定长度字符串(2 位),只能是  或 
  • Salary:数值类型(总长度 10,小数位 2),范围 3000-50000
  • HireDate:日期类型,默认值为系统当前日期

答案 & 解析

CREATE TABLE Employee (
    EmpID INT IDENTITY(1,1) PRIMARY KEY, -- 主键 + 自增(1 开始,步长 1)
    EmpName VARCHAR(50) NOT NULL UNIQUE, -- 非空 + 唯一约束
    Gender CHAR(2) NOT NULL,
    Salary DECIMAL(10,2) NOT NULL,
    HireDate DATE DEFAULT GETDATE(), -- 默认当前日期
    CONSTRAINT CK_Employee_Gender CHECK (Gender IN ('男', '女')), -- 检查性别
    CONSTRAINT CK_Employee_Salary CHECK (Salary >= 3000 AND Salary <= 50000) -- 检查工资范围
);

考点

  • 主键自增(IDENTITY)、唯一约束(UNIQUE)的组合
  • 检查约束(CHECK)的多条件应用
  • 默认约束(DEFAULT)结合系统函数(GETDATE()

练习二:外键约束与级联操作

题目
现有 Department 表(主表)和 Employee 表(从表),要求:

  1. Department 表结构:
    • DeptID(主键,整数)、DeptName(非空,唯一,长度 50)
  2. Employee 表结构:
    • EmpID(主键,整数)、EmpName(非空)、DeptID(外键,关联 Department 表的 DeptID
    • 当删除 Department 表中的部门时,自动删除该部门下的所有员工(级联删除)

答案 & 解析

-- 1. 创建主表 Department
CREATE TABLE Department (
    DeptID INT PRIMARY KEY,
    DeptName VARCHAR(50) NOT NULL UNIQUE
);

-- 2. 创建从表 Employee,定义外键 + 级联删除
CREATE TABLE Employee (
    EmpID INT PRIMARY KEY,
    EmpName VARCHAR(50) NOT NULL,
    DeptID INT,
    CONSTRAINT FK_Employee_DeptID 
        FOREIGN KEY (DeptID) 
        REFERENCES Department(DeptID)
        ON DELETE CASCADE -- 级联删除:删部门时自动删员工
);

考点

  • 外键约束(FOREIGN KEY)的基本用法
  • 级联操作(ON DELETE CASCADE)的应用场景
  • 主表与从表的关联逻辑

练习三:复合约束(复合主键 + 多列唯一)

题目
创建 CourseScore 表,记录学生课程成绩,要求:

  • StudentID(长度 12 的字符串)、CourseID(长度 6 的字符串)、Score(数值,0-100)
  • 约束:
    • StudentID + CourseID 组合为复合主键(保证一人一门课只有一条成绩)
    • Score 列值必须 ≥0 且 ≤100
    • 额外要求:同一门课的成绩,不能有重复的学生(即 CourseID + StudentID 唯一,和复合主键逻辑一致,强化理解)

答案 & 解析

CREATE TABLE CourseScore (
    StudentID NCHAR(12) NOT NULL,
    CourseID NCHAR(6) NOT NULL,
    Score NUMERIC(5,1) NOT NULL,
    -- 复合主键:(StudentID, CourseID)
    CONSTRAINT PK_CourseScore PRIMARY KEY (StudentID, CourseID), 
    -- 检查成绩范围
    CONSTRAINT CK_CourseScore_Score CHECK (Score >= 0 AND Score <= 100), 
    -- 多列唯一(和复合主键效果一致,练习语法)
    CONSTRAINT UQ_CourseScore UNIQUE (StudentID, CourseID) 
);

考点

  • 复合主键(多列组合主键)的定义
  • 多列唯一约束(UNIQUE 用于多列)
  • 检查约束对数值范围的限制

练习四:约束修改与删除(进阶操作)

题目
针对已存在的 Employee 表(结构如下),完成以下操作:

CREATE TABLE Employee (
    EmpID INT PRIMARY KEY,
    EmpName VARCHAR(50) NOT NULL,
    Salary DECIMAL(10,2) NOT NULL,
    HireDate DATE
);
  1. 添加约束:
    • EmpName 列值唯一
    • Salary 列范围 5000-60000
    • HireDate 列默认值为系统当前日期
  2. 删除 EmpName 列的唯一约束(假设约束名为 UQ_Employee_EmpName
  3. 修改 Salary 列的检查约束,将范围改为 4000-50000(需先删旧约束,再建新约束)

答案 & 解析

-- 1. 添加约束(分步执行)
ALTER TABLE Employee
ADD CONSTRAINT UQ_Employee_EmpName UNIQUE (EmpName); -- 唯一约束

ALTER TABLE Employee
ADD CONSTRAINT CK_Employee_Salary CHECK (Salary >= 5000 AND Salary <= 60000); -- 检查约束

ALTER TABLE Employee
ADD CONSTRAINT DF_Employee_HireDate DEFAULT GETDATE() FOR HireDate; -- 默认约束

-- 2. 删除唯一约束
ALTER TABLE Employee
DROP CONSTRAINT UQ_Employee_EmpName;

-- 3. 修改检查约束(先删旧,再建新)
ALTER TABLE Employee
DROP CONSTRAINT CK_Employee_Salary;

ALTER TABLE Employee
ADD CONSTRAINT CK_Employee_Salary CHECK (Salary >= 4000 AND Salary <= 50000);

考点

  • 用 ALTER TABLE 动态添加 / 删除约束
  • 检查约束的 “修改” 逻辑(需先删除旧约束)
  • 默认约束的添加语法(DEFAULT ... FOR 列名

练习五:约束冲突场景判断(选择题变形)

题目
现有 Student 表结构:

CREATE TABLE Student (
    SID INT PRIMARY KEY,
    SName VARCHAR(50) NOT NULL UNIQUE,
    Age INT CHECK (Age >= 18 AND Age <= 30),
    Gender CHAR(2) CHECK (Gender IN ('男', '女'))
);

判断以下插入操作是否会触发约束冲突(填 “是” 或 “否”):

操作语句 是否冲突 冲突类型(主键 / 唯一 / 检查 / 外键)
INSERT INTO Student VALUES (1, '张三', 20, '男'); -
INSERT INTO Student VALUES (1, '李四', 22, '女'); 主键冲突(SID 重复)
INSERT INTO Student VALUES (2, '张三', 21, '男'); 唯一约束冲突(SName 重复)
INSERT INTO Student VALUES (3, '王五', 17, '男'); 检查约束冲突(Age < 18)
INSERT INTO Student VALUES (4, '赵六', 25, '未知'); 检查约束冲突(Gender 不在允许值)

考点

  • 各类约束的冲突场景判断(主键重复、唯一列重复、检查条件不满足等)
  • 实际操作中对约束生效逻辑的理解

网站公告

今日签到

点亮在社区的每一天
去签到