SQL約束是數(shù)據(jù)庫設(shè)計(jì)的核心機(jī)制,用于強(qiáng)制數(shù)據(jù)完整性和業(yè)務(wù)規(guī)則。以下按約束類型分類解析,包含基礎(chǔ)語法、參數(shù)說明、應(yīng)用場景和實(shí)戰(zhàn)示例,僅供參考。
一、SQL約束的基礎(chǔ)概念
作用:在數(shù)據(jù)插入/更新時(shí)自動(dòng)校驗(yàn),防止非法數(shù)據(jù)破壞完整性
分類:
- 列級(jí)約束:直接定義在字段后(
CREATE TABLE
時(shí)) - 表級(jí)約束:獨(dú)立聲明在所有字段后(支持多字段組合約束)
共性特征: - 違反約束時(shí)操作被終止,拋出錯(cuò)誤代碼(如MySQL 1062主鍵沖突)
- 支持
CREATE TABLE
或ALTER TABLE
兩種定義方式
數(shù)據(jù)完整性類型:
二、SQL約束類型詳解
1. NOT NULL 約束
作用:禁止字段存儲(chǔ)NULL
值(空值 ≠ 0或空字符串)
語法:
-- 創(chuàng)建表時(shí)定義
CREATE TABLE 表名 (
字段名 數(shù)據(jù)類型 NOT NULL
);
-- 修改表結(jié)構(gòu)
ALTER TABLE 表名
MODIFY 字段名 數(shù)據(jù)類型 NOT NULL; -- MySQL/PostgreSQL
ALTER TABLE 表名
ALTER COLUMN 字段名 SET NOT NULL; -- SQL Server
重要特性:
- SQL Server嚴(yán)格區(qū)分
NULL
與''
實(shí)戰(zhàn)示例:
-- 創(chuàng)建用戶表
CREATE TABLE Users (
UserID INT PRIMARY KEY,
UserName VARCHAR(50) NOT NULL, -- 用戶名不能為空
BirthDate DATE NOT NULL -- 出生日期必填
);
-- 插入非法數(shù)據(jù)(觸發(fā)約束)
INSERT INTO Users (UserID, UserName)
VALUES (1, 'Alice');
-- 錯(cuò)誤: Column 'BirthDate' cannot be null
2. UNIQUE 約束
作用:確保字段值全表唯一(允許多個(gè)NULL
)
語法:
-- 單字段列級(jí)約束
CREATE TABLE 表名 (
字段名 數(shù)據(jù)類型 UNIQUE
);
-- 多字段表級(jí)約束
CREATE TABLE 表名 (
字段1 數(shù)據(jù)類型,
字段2 數(shù)據(jù)類型,
CONSTRAINT 約束名 UNIQUE (字段1, 字段2)
);
-- 修改表添加約束
ALTER TABLE 表名
ADD CONSTRAINT 約束名 UNIQUE (字段);
跨數(shù)據(jù)庫差異:
實(shí)戰(zhàn)示例:
-- 創(chuàng)建員工郵箱表
CREATE TABLE Employees (
EmpID INT PRIMARY KEY,
Email VARCHAR(100) UNIQUE, -- 郵箱唯一
Phone VARCHAR(20)
);
-- 添加復(fù)合唯一約束(部門+工號(hào))
ALTER TABLE Employees
ADD CONSTRAINT uniq_dept_emp
UNIQUE (DeptID, EmpCode);
-- 插入沖突數(shù)據(jù)
INSERT INTO Employees (EmpID, Email)
VALUES (1, 'alice@company.com');
INSERT INTO Employees (EmpID, Email)
VALUES (2, 'alice@company.com');
-- 錯(cuò)誤: Duplicate entry 'alice@company.com'
3. PRIMARY KEY 約束
作用:唯一標(biāo)識(shí)行數(shù)據(jù)(NOT NULL + UNIQUE)
語法:
-- 單字段主鍵
CREATE TABLE 表名 (
字段名 數(shù)據(jù)類型 PRIMARY KEY -- 列級(jí)
);
-- 多字段主鍵(表級(jí))
CREATE TABLE 表名 (
字段1 數(shù)據(jù)類型,
字段2 數(shù)據(jù)類型,
CONSTRAINT pk_name PRIMARY KEY (字段1, 字段2)
);
-- 添加主鍵
ALTER TABLE 表名
ADD PRIMARY KEY (字段); -- 匿名約束
ALTER TABLE 表名
ADD CONSTRAINT pk_name PRIMARY KEY (字段);
核心規(guī)則:
- 主鍵字段自動(dòng)創(chuàng)建唯一索引
實(shí)戰(zhàn)示例:
-- 創(chuàng)建訂單表
CREATE TABLE Orders (
OrderID INT PRIMARY KEY, -- 列級(jí)主鍵
OrderDate DATE NOT NULL
);
-- 創(chuàng)建訂單詳情(復(fù)合主鍵)
CREATE TABLE OrderDetails (
OrderID INT,
ProductID INT,
Quantity INT,
CONSTRAINT pk_order_product
PRIMARY KEY (OrderID, ProductID) -- 表級(jí)
);
-- 非法數(shù)據(jù)插入
INSERT INTO Orders (OrderID, OrderDate)
VALUES (1, '2023-01-01');
INSERT INTO Orders (OrderID, OrderDate)
VALUES (1, '2023-02-01');
-- 錯(cuò)誤: Duplicate entry '1'for key 'PRIMARY'
4. FOREIGN KEY 約束
作用:強(qiáng)制表間引用完整性(子表引用父表主鍵)
語法:
-- 創(chuàng)建表時(shí)定義
CREATE TABLE 子表 (
子表字段 數(shù)據(jù)類型,
CONSTRAINT fk_name
FOREIGN KEY (子表字段)
REFERENCES 父表(父表字段)
[ON DELETE 動(dòng)作] -- 級(jí)聯(lián)操作
[ON UPDATE 動(dòng)作]
);
-- 添加外鍵
ALTER TABLE 子表
ADD CONSTRAINT fk_name
FOREIGN KEY (子表字段)
REFERENCES 父表(父表字段);
級(jí)聯(lián)操作(可選):
| |
---|
NO ACTION | 禁止刪除/更新被引數(shù)據(jù)(默認(rèn)) |
CASCADE | 級(jí)聯(lián)刪除/更新子表數(shù)據(jù) |
SET NULL | |
SET DEFAULT | |
實(shí)戰(zhàn)示例:
-- 父表:部門
CREATE TABLE Departments (
DeptID INT PRIMARY KEY,
DeptName VARCHAR(50)
);
-- 子表:員工(帶級(jí)聯(lián)刪除)
CREATE TABLE Employees (
EmpID INT PRIMARY KEY,
DeptID INT,
CONSTRAINT fk_emp_dept
FOREIGN KEY (DeptID)
REFERENCES Departments(DeptID)
ON DELETE CASCADE -- 部門刪除時(shí)員工自動(dòng)刪除
);
-- 插入關(guān)聯(lián)數(shù)據(jù)
INSERT INTO Departments VALUES (1, 'IT');
INSERT INTO Employees VALUES (101, 1);
-- 測試級(jí)聯(lián)刪除
DELETE FROM Departments WHERE DeptID = 1;
-- 結(jié)果:Employees中EmpID=101的記錄自動(dòng)刪除
5. CHECK 約束
作用:定義字段值的業(yè)務(wù)規(guī)則(類似WHERE
條件)
語法:
-- 列級(jí)約束
CREATE TABLE 表名 (
字段名 數(shù)據(jù)類型 CHECK (條件)
);
-- 表級(jí)多字段約束
CREATE TABLE 表名 (
字段1 數(shù)據(jù)類型,
字段2 數(shù)據(jù)類型,
CONSTRAINT chk_name CHECK (字段1 > 字段2)
);
-- 添加約束
ALTER TABLE 表名
ADD CONSTRAINT chk_name CHECK (條件);
特殊規(guī)則:
- 條件中可調(diào)用函數(shù)(如
GETDATE()
) - SQLite僅支持
CREATE TABLE
時(shí)定義
實(shí)戰(zhàn)示例:
-- 創(chuàng)建賬戶表
CREATE TABLE Accounts (
AccountID INT PRIMARY KEY,
Balance DECIMAL(10,2) CHECK (Balance >= 0), -- 余額不可負(fù)
Status VARCHAR(10) CHECK (Status IN ('ACTIVE', 'CLOSED'))
);
-- 添加自定義規(guī)則(開戶日期早于今日)
ALTER TABLE Accounts
ADD CONSTRAINT chk_open_date
CHECK (OpenDate < GETDATE());
-- 違反約束測試
INSERT INTO Accounts
VALUES (1, -100.00, 'ACTIVE');
-- 錯(cuò)誤: Check constraint 'Balance>=0' violated
6. DEFAULT 約束
作用:字段未賦值時(shí)自動(dòng)填充默認(rèn)值
語法:
-- 創(chuàng)建表時(shí)定義
CREATE TABLE 表名 (
字段名 數(shù)據(jù)類型 DEFAULT 默認(rèn)值
);
-- 修改默認(rèn)值
ALTER TABLE 表名
ALTER COLUMN 字段名 SET DEFAULT 值; -- MySQL/PostgreSQL
ALTER TABLE 表名
ADD CONSTRAINT 約束名 DEFAULT 值 FOR 字段; -- SQL Server
常用默認(rèn)值:
- 系統(tǒng)函數(shù):
DEFAULT GETDATE()
(當(dāng)前時(shí)間) - 表達(dá)式:
DEFAULT (UUID())
(生成唯一ID)
實(shí)戰(zhàn)示例:
-- 創(chuàng)建用戶注冊(cè)表
CREATE TABLE Registrations (
UserID INT PRIMARY KEY,
RegDate DATE DEFAULT GETDATE(), -- 自動(dòng)填充注冊(cè)日期
Status VARCHAR(10) DEFAULT 'PENDING'
);
-- 插入數(shù)據(jù)(忽略默認(rèn)字段)
INSERT INTO Registrations (UserID) VALUES (1001);
-- 查詢結(jié)果
SELECT * FROM Registrations;
/*
UserID | RegDate | Status
1001 | 2023-10-05 | PENDING
*/
7. INDEX(索引)
嚴(yán)格說索引非約束,但用于加速唯一性校驗(yàn)
作用:快速定位數(shù)據(jù)(UNIQUE/PRIMARY KEY自動(dòng)創(chuàng)建)
語法:
CREATE INDEX 索引名 ON 表名 (字段);
CREATE UNIQUE INDEX 索引名 ON 表名 (字段); -- 唯一索引
與約束關(guān)系:
三、SQL約束管理技巧
1. 查看約束
-- SQL Server
SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS;
-- MySQL
SHOW CREATE TABLE 表名;
2. 刪除約束
ALTER TABLE 表名 DROP CONSTRAINT 約束名; -- 通用
ALTER TABLE 表名 DROP PRIMARY KEY; -- 主鍵
ALTER TABLE 表名 DROP INDEX 索引名; -- 索引
3. 臨時(shí)禁用約束
-- MySQL外鍵開關(guān)
SET FOREIGN_KEY_CHECKS = 0; -- 關(guān)閉
SET FOREIGN_KEY_CHECKS = 1; -- 開啟
-- SQL Server
ALTER TABLE 表名 NOCHECK CONSTRAINT ALL;
4. 約束設(shè)計(jì)建議
- 主鍵用無意義數(shù)字(自增ID/UUID),避免業(yè)務(wù)字段
- 慎用
ON DELETE CASCADE
(避免誤刪連鎖反應(yīng)) - CHECK約束優(yōu)先于應(yīng)用層校驗(yàn)(保證數(shù)據(jù)純凈性)
綜合實(shí)戰(zhàn):學(xué)生管理系統(tǒng)
-- 學(xué)院表(父表)
CREATE TABLE Colleges (
CollegeID INT PRIMARY KEY,
Name VARCHAR(50) NOT NULL UNIQUE
);
-- 學(xué)生表(子表)
CREATE TABLE Students (
StudentID INT PRIMARY KEY,
Name VARCHAR(50) NOT NULL,
IDCard CHAR(18) UNIQUE, -- 身份證唯一
CollegeID INT NOT NULL,
EnrollmentDate DATE DEFAULT GETDATE(),
GPA DECIMAL(3,2) CHECK (GPA BETWEEN 0 AND 4.0),
-- 表級(jí)外鍵(級(jí)聯(lián)更新)
CONSTRAINT fk_student_college
FOREIGN KEY (CollegeID)
REFERENCES Colleges(CollegeID)
ON UPDATE CASCADE
);
-- 課程表
CREATE TABLE Courses (
CourseID INT PRIMARY KEY,
Credit INT CHECK (Credit > 0) -- 學(xué)分需正數(shù)
);
-- 插入測試數(shù)據(jù)
INSERT INTO Colleges VALUES (1, '計(jì)算機(jī)學(xué)院');
INSERT INTO Students (StudentID, Name, CollegeID)
VALUES (1001, '張三', 1); -- 自動(dòng)填充注冊(cè)日期
-- 錯(cuò)誤測試:無效學(xué)院
INSERT INTO Students VALUES (1002, '李四', '310101...', 99, '2023-09-01', 3.8);
-- 報(bào)錯(cuò): Foreign key constraint violation
系統(tǒng)約束清單:
- 學(xué)院更新時(shí)自動(dòng)同步到學(xué)生表
總結(jié)
SQL約束是數(shù)據(jù)庫的“守門員”,通過七類機(jī)制保障數(shù)據(jù)質(zhì)量:
- NOT NULL:強(qiáng)制關(guān)鍵字段必填
- UNIQUE:防止重復(fù)數(shù)據(jù)(如身份證)
- PRIMARY KEY:確立數(shù)據(jù)唯一標(biāo)識(shí)
- FOREIGN KEY:維護(hù)表間引用關(guān)系
- CHECK:實(shí)現(xiàn)業(yè)務(wù)規(guī)則(如GPA范圍)
我們要合理使用SQL約束減少應(yīng)用層校驗(yàn)代碼,從根本上杜絕臟數(shù)據(jù)。
閱讀原文:原文鏈接
該文章在 2025/9/1 12:06:37 編輯過