SQL(结构化查询语言)是管理与操作关系型数据库的基石。为了高效地进行系统性的学习和应用,我们通常将SQL语句按其核心功能划分为五大类别:数据定义语言(DDL)、数据操作语言(DML)、数据查询语言(DQL)、数据控制语言(DCL)以及事务控制语言(TCL)。理解这五类语句各自扮演的角色,是掌握数据库开发与管理的关键第一步。
下面,我们将通过一个贯穿始终的模拟公司数据库案例,详细拆解每一类语句的基础语法、应用场景及实战技巧。为了更清晰地展示,我们会先构建这个模拟环境。
一、创建模拟数据库
1. 数据库结构
首先,我们创建数据库及相关的核心表结构,这主要会用到DDL语句。
-- 创建数据库
CREATE DATABASE company_db;
USE company_db;
-- DDL:部门表
CREATE TABLE departments (
dept_id INT PRIMARY KEY AUTO_INCREMENT,
dept_name VARCHAR(50) NOT NULL UNIQUE,
location VARCHAR(100) DEFAULT ‘Headquarters’,
annual_budget DECIMAL(15,2) CHECK (annual_budget >= 0),
established_date DATE NOT NULL
);
-- DDL:员工表
CREATE TABLE employees (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
email VARCHAR(100) UNIQUE,
hire_date DATE DEFAULT (CURRENT_DATE),
dept_id INT,
salary DECIMAL(10,2) NOT NULL CHECK (salary > 0),
bonus DECIMAL(10,2) DEFAULT 0.00,
CONSTRAINT fk_dept
FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
) ENGINE=InnoDB;
-- DDL:薪资历史表
CREATE TABLE salary_history (
record_id INT AUTO_INCREMENT PRIMARY KEY,
emp_id INT NOT NULL,
old_salary DECIMAL(10,2),
new_salary DECIMAL(10,2) NOT NULL,
change_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT fk_emp_salary
FOREIGN KEY (emp_id) REFERENCES employees(emp_id)
);
-- DDL:用户表
CREATE TABLE users (
user_id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) UNIQUE NOT NULL,
role VARCHAR(50) DEFAULT ‘staff’
);
2. 插入模拟数据
数据库结构建好后,我们用DML语句为其填充初始数据。
-- DML:插入部门数据
INSERT INTO departments (dept_name, location, annual_budget, established_date)
VALUES
(‘Engineering’, ‘San Francisco’, 1500000.00, ‘2010-05-15’),
(‘Marketing’, ‘New York’, 800000.00, ‘2012-02-20’),
(‘Human Resources’, ‘Chicago’, 500000.00, ‘2015-08-10’);
-- DML:插入员工数据
INSERT INTO employees (first_name, last_name, email, hire_date, dept_id, salary)
VALUES
(‘Alice’, ‘Chen’, ‘alice.chen@company.com’, ‘2020-03-15’, 1, 95000.00),
(‘Robert’, ‘Wilson’, ‘robert.w@company.com’, ‘2018-11-22’, 1, 115000.00),
(‘Emily’, ‘Davis’, ‘emily.davis@company.com’, ‘2022-01-10’, 2, 75000.00),
(‘James’, ‘Johnson’, ‘james.j@company.com’, ‘2019-06-05’, 3, 65000.00);
-- DML:插入用户数据
INSERT INTO users (username, role)
VALUES
(‘admin1’, ‘administrator’),
(‘hr_user’, ‘hr_manager’),
(‘dev_user’, ‘engineering’);
环境准备就绪,现在让我们正式进入五大操作类别的学习。
二、DDL(数据定义语言)
DDL用于定义和修改数据库对象(如表、索引)的结构。其主要特点是执行后通常会自动提交,难以回滚。
1. CREATE TABLE
基础语法:
CREATE TABLE table_name (
column1 datatype [column_constraint],
column2 datatype [column_constraint],
...
[table_constraints]
);
语法元素:
| 元素 |
描述 |
参数/选项 |
datatype |
列数据类型 |
INT, VARCHAR(n), DECIMAL(p,s), DATE, TIMESTAMP等 |
PRIMARY KEY |
定义主键 |
单列主键直接在列后声明 |
FOREIGN KEY |
定义外键 |
REFERENCES parent_table(parent_column) |
NOT NULL |
不允许空值 |
强制列必须有值 |
UNIQUE |
唯一约束 |
确保列值不重复 |
CHECK |
条件约束 |
CHECK (condition) |
DEFAULT |
默认值 |
DEFAULT value |
AUTO_INCREMENT |
自增列(MySQL) |
常用于主键 |
应用示例:
-- 创建项目表
CREATE TABLE projects (
project_id INT AUTO_INCREMENT PRIMARY KEY,
project_name VARCHAR(100) NOT NULL UNIQUE,
start_date DATE NOT NULL,
end_date DATE,
dept_id INT NOT NULL,
budget DECIMAL(10,2) CHECK (budget > 0),
status ENUM(‘Planning’, ‘Active’, ‘Completed’) DEFAULT ‘Planning’,
CONSTRAINT fk_dept_projects
FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
);
模拟输出:
DESCRIBE projects;
/*
+--------------+-------------------------------+------+-----+------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------------------------+------+-----+------------+----------------+
| project_id | int(11) | NO | PRI | NULL | auto_increment |
| project_name | varchar(100) | NO | UNI | NULL | |
| start_date | date | NO | | NULL | |
| end_date | date | YES | | NULL | |
| dept_id | int(11) | NO | MUL | NULL | |
| budget | decimal(10,2) | YES | | NULL | |
| status | enum(‘Planning’,‘Active’,‘Completed’) | YES | | Planning | |
+--------------+-------------------------------+------+-----+------------+----------------+
*/
2. ALTER TABLE
当业务需求变化时,ALTER TABLE 允许我们动态调整已有表的结构。
基础语法:
-- 添加列
ALTER TABLE table_name
ADD COLUMN column_name datatype [constraints];
-- 修改列 (MySQL)
ALTER TABLE table_name
MODIFY COLUMN column_name new_datatype;
-- 修改列 (PostgreSQL)
ALTER TABLE table_name
ALTER COLUMN column_name TYPE new_datatype;
-- 删除列
ALTER TABLE table_name
DROP COLUMN column_name;
-- 添加约束
ALTER TABLE table_name
ADD CONSTRAINT constraint_name constraint_definition;
-- 删除约束
ALTER TABLE table_name
DROP CONSTRAINT constraint_name;
应用示例:
-- 添加项目经理列
ALTER TABLE projects
ADD COLUMN manager_id INT,
ADD CONSTRAINT fk_project_manager
FOREIGN KEY (manager_id) REFERENCES employees(emp_id);
-- 修改预算精度
ALTER TABLE projects
MODIFY budget DECIMAL(12,2);
-- 添加检查约束
ALTER TABLE employees
ADD CONSTRAINT chk_bonus
CHECK (bonus >= 0 AND bonus <= salary * 0.3);
3. DROP & TRUNCATE
这两个命令都用于删除数据,但行为有本质区别。
基础语法:
-- 删除表(结构和数据)
DROP TABLE table_name [RESTRICT|CASCADE];
-- 清空表(仅数据,保留结构)
TRUNCATE TABLE table_name;
应用示例:
-- 删除临时表
DROP TABLE temp_report_data;
-- 清空日志表
TRUNCATE TABLE debug_logs;
注意事项:
DROP 删除整个表结构和数据。
TRUNCATE 保留表结构,删除所有数据,效率通常比 DELETE 高。
- 在MySQL中,
TRUNCATE 不能回滚,而在 PostgreSQL 中则可以。
三、DML(数据操作语言)
DML用于对表中的数据进行增、删、改操作。这些操作通常需要在事务(TCL)中进行显式控制,以保证数据的一致性。
1. INSERT
基础语法:
-- 完整形式(为所有列赋值)
INSERT INTO table_name VALUES (value1, value2, ...);
-- 指定列插入(更安全、清晰)
INSERT INTO table_name (column1, column2, ...)
VALUES (value1, value2, ...);
-- 多行插入(提升效率)
INSERT INTO table_name (column1, column2, ...)
VALUES
(value1a, value2a, ...),
(value1b, value2b, ...);
-- 从查询结果插入
INSERT INTO table_name (column1, column2, ...)
SELECT ...;
应用示例:
-- 插入项目数据
INSERT INTO projects (project_name, start_date, dept_id, budget)
VALUES
(‘CRM System’, ‘2023-01-15’, 1, 200000.00),
(‘Marketing Campaign’, ‘2023-03-01’, 2, 50000.00);
-- 为经理分配项目(结合UPDATE)
UPDATE projects
SET manager_id = (
SELECT emp_id FROM employees
WHERE email = ‘robert.w@company.com’
)
WHERE project_name = ‘CRM System’;
模拟输出:
SELECT * FROM projects;
/*
+------------+-------------------+------------+----------+---------+-----------+----------+------------+
| project_id | project_name | start_date | end_date | dept_id | budget | status | manager_id |
+------------+-------------------+------------+----------+---------+-----------+----------+------------+
| 1 | CRM System | 2023-01-15 | NULL | 1 | 200000.00 | Planning | 2 |
| 2 | Marketing Campaign| 2023-03-01 | NULL | 2 | 50000.00 | Planning | NULL |
+------------+-------------------+------------+----------+---------+-----------+----------+------------+
*/
2. UPDATE
用于修改表中已存在的数据。切记使用 WHERE 子句,否则将更新所有行!
基础语法:
UPDATE table_name
SET
column1 = value1,
column2 = value2,
...
[WHERE condition]
[ORDER BY ...] -- MySQL特有,用于控制更新顺序
[LIMIT count]; -- MySQL特有,用于分批更新
应用示例:
-- 普通条件更新:为2022年前入职的员工发奖金
UPDATE employees
SET bonus = salary * 0.1
WHERE hire_date < ‘2022-01-01’;
-- 关联更新:为CRM系统项目经理加薪
UPDATE employees e
JOIN projects p ON e.emp_id = p.manager_id
SET e.salary = e.salary * 1.15
WHERE p.project_name = ‘CRM System’;
-- 基于子查询和函数更新
UPDATE projects
SET end_date = DATE_ADD(start_date, INTERVAL 6 MONTH),
status = ‘Active’
WHERE project_id = 1;
模拟输出:
-- 更新后查询
SELECT emp_id, first_name, salary, bonus
FROM employees
WHERE emp_id = 2;
/*
+--------+------------+-----------+--------+
| emp_id | first_name | salary | bonus |
+--------+------------+-----------+--------+
| 2 | Robert | 132250.00 | 11500 |
+--------+------------+-----------+--------+
*/
3. DELETE
用于从表中删除行。同样,WHERE 子句至关重要,避免误删全部数据。
基础语法:
DELETE FROM table_name
[WHERE condition]
[ORDER BY ...]
[LIMIT row_count];
应用示例:
-- 删除测试用户
DELETE FROM users
WHERE username LIKE ‘test_%’;
-- 使用子查询:删除没有项目且成立较早的部门
DELETE FROM departments
WHERE dept_id NOT IN (SELECT dept_id FROM projects)
AND established_date < ‘2020-01-01’;
-- 简单条件删除
DELETE FROM projects
WHERE budget < 10000;
四、DQL(数据查询语言)
DQL的核心是 SELECT 语句,用于从数据库中检索数据。它是SQL中使用最频繁、功能最丰富的部分。
1. SELECT基础结构
完整语法:
SELECT
[DISTINCT] column1 [AS alias],
aggregate_function(column2),
expression
FROM table1
[JOIN table2 ON join_condition]
[WHERE conditions]
[GROUP BY grouping_columns]
[HAVING group_conditions]
[ORDER BY sort_columns [ASC|DESC]]
[OFFSET start]
[LIMIT count]
[FOR UPDATE];
2. JOIN连接
连接是将多个表的数据关联起来的强大工具。
连接类型:
-- 内连接(默认):仅返回匹配的行
SELECT ... FROM table1
[INNER] JOIN table2 ON condition
-- 左外连接:返回左表所有行,右表无匹配则为NULL
SELECT ... FROM table1
LEFT [OUTER] JOIN table2 ON condition
-- 右外连接:返回右表所有行,左表无匹配则为NULL
SELECT ... FROM table1
RIGHT [OUTER] JOIN table2 ON condition
-- 全外连接:返回左右表所有行(MySQL不支持,可用UNION模拟)
-- 交叉连接:返回笛卡尔积
SELECT ... FROM table1
CROSS JOIN table2
应用示例:
-- 多表连接查询员工、部门和项目信息
SELECT
e.emp_id,
CONCAT(e.first_name, ‘ ‘, e.last_name) AS employee,
d.dept_name,
p.project_name,
p.budget
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id
LEFT JOIN projects p ON e.emp_id = p.manager_id;
模拟输出:
+--------+-----------------+--------------+-------------------+-----------+
| emp_id | employee | dept_name | project_name | budget |
+--------+-----------------+--------------+-------------------+-----------+
| 1 | Alice Chen | Engineering | NULL | NULL |
| 2 | Robert Wilson | Engineering | CRM System | 200000.00 |
| 3 | Emily Davis | Marketing | NULL | NULL |
| 4 | James Johnson | Human Resources| NULL | NULL |
+--------+-----------------+--------------+-------------------+-----------+
3. 聚合与分组
用于对数据进行统计和汇总分析。
常用聚合函数:
| 函数 |
描述 |
示例 |
COUNT() |
计数 |
COUNT(*) |
SUM() |
求和 |
SUM(salary) |
AVG() |
平均值 |
AVG(salary) |
MIN() |
最小值 |
MIN(hire_date) |
MAX() |
最大值 |
MAX(salary) |
GROUP_CONCAT() |
分组连接字符串 |
GROUP_CONCAT(name SEPARATOR ‘, ‘) |
应用示例:
-- 部门薪资分析:统计人数、总薪酬、平均薪资等
SELECT
d.dept_name,
COUNT(e.emp_id) AS num_employees,
SUM(e.salary + e.bonus) AS total_compensation,
AVG(e.salary) AS avg_salary,
MIN(e.hire_date) AS earliest_hire,
GROUP_CONCAT(e.first_name SEPARATOR ‘, ‘) AS team_members
FROM departments d
LEFT JOIN employees e ON d.dept_id = e.dept_id
GROUP BY d.dept_id
HAVING COUNT(e.emp_id) > 1; -- HAVING对分组结果进行过滤
4. 窗口函数
窗口函数在不聚合数据的前提下,为每一行提供基于“窗口”(一组相关行)的计算结果,非常适合排名、累计、移动平均等分析场景。
常用窗口函数:
| 函数 |
描述 |
ROW_NUMBER() |
分区内序号(唯一) |
RANK() |
带间隔排名(并列跳号) |
DENSE_RANK() |
无间隔排名(并列不跳号) |
LEAD() / LAG() |
获取下一行/上一行的值 |
SUM() OVER() |
计算累计和 |
应用示例:
-- 部门内薪资排名及占比分析
SELECT
emp_id,
CONCAT(first_name, ‘ ‘, last_name) AS employee,
dept_id,
salary,
bonus,
salary + bonus AS total_comp,
RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS dept_rank,
ROUND(salary * 100 / SUM(salary) OVER (PARTITION BY dept_id), 2) AS salary_percent,
AVG(salary) OVER (PARTITION BY dept_id) AS dept_avg
FROM employees;
五、DCL(数据控制语言)
DCL用于管理数据库的访问权限和安全,核心是控制“谁”能对“什么”对象执行“哪些”操作。
权限管理
基础语法:
-- 创建角色
CREATE ROLE role_name;
-- 授予权限
GRANT privilege_type ON object TO user_or_role
[WITH GRANT OPTION]; -- 允许被授权者继续授权
-- 撤销权限
REVOKE privilege_type ON object
FROM user_or_role;
-- 查看权限
SHOW GRANTS FOR username;
| 常用权限类型: |
权限 |
描述 |
SELECT, INSERT, UPDATE, DELETE |
数据操作权限 |
CREATE, ALTER, DROP |
结构操作权限 |
ALL PRIVILEGES |
所有权限 |
应用示例:
-- 创建HR管理员角色
CREATE ROLE hr_admin;
-- 授予角色对员工表的读写权限,对部门表的只读权限
GRANT SELECT, INSERT, UPDATE
ON employees
TO hr_admin;
GRANT SELECT
ON departments
TO hr_admin;
-- 将角色分配给具体用户
GRANT hr_admin TO hr_user;
-- 回收部分权限
REVOKE UPDATE
ON employees
FROM hr_admin;
六、TCL(事务控制语言)
TCL用于管理数据库事务,确保一系列DML操作要么全部成功,要么全部失败,维护数据的完整性和一致性。
1. 事务基础语法
-- 开始事务
BEGIN; -- 或 START TRANSACTION
-- 提交事务,使所有更改永久生效
COMMIT;
-- 回滚事务,撤销所有未提交的更改
ROLLBACK;
-- 设置保存点,用于部分回滚
SAVEPOINT savepoint_name;
ROLLBACK TO savepoint_name;
-- 设置事务隔离级别
SET TRANSACTION ISOLATION LEVEL level;
2. 隔离级别
不同级别在性能和数据一致性之间提供不同权衡:
| 级别 |
脏读 |
不可重复读 |
幻读 |
READ UNCOMMITTED |
可能 |
可能 |
可能 |
READ COMMITTED |
不可能 |
可能 |
可能 |
REPEATABLE READ (MySQL默认) |
不可能 |
不可能 |
可能 |
SERIALIZABLE |
不可能 |
不可能 |
不可能 |
3. 应用示例
-- 薪资调整事务:包含业务逻辑检查和回滚点
BEGIN;
-- 设置保存点
SAVEPOINT before_updates;
-- 更新员工薪资
UPDATE employees
SET salary = salary * 1.05
WHERE dept_id = 1;
-- 记录薪资变更历史
INSERT INTO salary_history (emp_id, old_salary, new_salary)
SELECT emp_id, salary/1.05, salary
FROM employees
WHERE dept_id = 1;
-- 业务规则检查:如果总薪资超预算,则回滚到保存点
IF (SELECT SUM(salary) FROM employees) > 500000 THEN
ROLLBACK TO before_updates;
INSERT INTO error_log (message) VALUES (‘Salary budget exceeded’);
END IF;
-- 检查通过,提交事务
COMMIT;
七、总结与最佳实践
SQL五大操作对比表:
| 类别 |
核心语句 |
事务控制 |
主要应用场景 |
| DDL |
CREATE, ALTER, DROP |
通常自动提交 |
数据库设计与结构调整 |
| DML |
INSERT, UPDATE, DELETE |
需显式控制 |
日常数据维护与操作 |
| DQL |
SELECT, JOIN, WHERE |
只读 |
数据查询与分析 |
| DCL |
GRANT, REVOKE |
自动提交 |
权限管理与安全控制 |
| TCL |
COMMIT, ROLLBACK, SAVEPOINT |
事务边界控制 |
数据一致性与完整性保障 |
应用建议:
- 结构变更:在生产环境执行DDL前,务必在测试环境验证,并考虑使用在线DDL工具或低峰期操作。
- 数据操作:进行大批量DML操作时,采用分批提交(如每1000行一次
COMMIT)并利用 LIMIT 子句,避免长事务和锁表。
- 查询优化:编写复杂DQL时,养成先用
EXPLAIN 分析执行计划的习惯,合理使用索引。更多优化技巧可以参考云栈社区的 技术文档 专题。
- 权限管理:遵循最小权限原则,使用角色管理权限,定期审计权限分配。
- 事务控制:明确事务边界,避免在事务中进行耗时操作(如远程调用),并设置合理的超时和死锁处理机制。
掌握SQL五大操作类别,并能根据具体场景(如使用 MySQL 或 PostgreSQL)灵活运用其语法差异,是每一位后端开发者和数据库管理员的必备技能。希望这篇结合实例的详解能帮助你构建起清晰的知识框架。