在 SQL Server 中,约束(Constraint) 是用于确保数据库中数据的完整性、一致性和有效性的规则。它们可以防止无效数据进入表中,保证数据质量,让数据库的结构和内容更合理、可靠。以下从常见约束类型、作用、语法和使用场景等方面详细讲解:
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 是主键缩写
);
(ID, ClassID)
,需保证组合值唯一 )。INT
、BIGINT
或带唯一性的字符类型(如 CHAR(10)
),方便快速检索。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 是唯一约束缩写
);
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
,让从表数据自动同步变更,避免破坏关联 )。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)
);
CHECK
约束的 “严格性” 有特殊点:默认情况下,CHECK
约束不阻止 NULL
值(除非列本身设了 NOT NULL
)。比如列设了 CHECK (Score >= 0)
,但 Score
允许 NULL
,就可以插入 NULL
值。DEFAULT
)正常
。CREATE TABLE Student (
ID INT PRIMARY KEY,
Name VARCHAR(50),
EnrollDate DATETIME DEFAULT GETDATE(), -- 调用 GETDATE() 函数,默认填当前时间
Status VARCHAR(10) DEFAULT '正常' -- 默认填 '正常'
);
'正常'
),也可以是函数(如 GETDATE()
获取当前时间 )。CREATE TABLE
语句里,和列定义写在一起(如前面的示例 )。ALTER TABLE
语句,适合表已存在,后续补充约束的场景。Student
表加唯一约束): ALTER TABLE Student
ADD CONSTRAINT UQ_Student_Phone UNIQUE (Phone);
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);
用 ALTER TABLE ... DROP CONSTRAINT ...
语法,指定约束名即可。
示例:
ALTER TABLE Student
DROP CONSTRAINT UQ_Student_Phone; -- 删除唯一约束 UQ_Student_Phone
PK_
、UQ_
、FK_
、CK_
),方便区分类型,也便于后续管理(比如 PK_StudentID
一看就知道是学生表的主键 )。CHECK
约束和复合外键 )会增加数据库的计算负担,插入、更新数据时变慢。需在 “数据完整性” 和 “性能” 之间找平衡。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
表(从表),要求:
Department
表结构:
DeptID
(主键,整数)、DeptName
(非空,唯一,长度 50)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 且 ≤100CourseID + 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
);
EmpName
列值唯一Salary
列范围 5000-60000
HireDate
列默认值为系统当前日期EmpName
列的唯一约束(假设约束名为 UQ_Employee_EmpName
)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 不在允许值) |
考点: