找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

852

积分

0

好友

120

主题
发表于 4 小时前 | 查看: 1| 回复: 0

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 事务边界控制 数据一致性与完整性保障

应用建议:

  1. 结构变更:在生产环境执行DDL前,务必在测试环境验证,并考虑使用在线DDL工具或低峰期操作。
  2. 数据操作:进行大批量DML操作时,采用分批提交(如每1000行一次COMMIT)并利用 LIMIT 子句,避免长事务和锁表。
  3. 查询优化:编写复杂DQL时,养成先用 EXPLAIN 分析执行计划的习惯,合理使用索引。更多优化技巧可以参考云栈社区的 技术文档 专题。
  4. 权限管理:遵循最小权限原则,使用角色管理权限,定期审计权限分配。
  5. 事务控制:明确事务边界,避免在事务中进行耗时操作(如远程调用),并设置合理的超时和死锁处理机制。

掌握SQL五大操作类别,并能根据具体场景(如使用 MySQL 或 PostgreSQL)灵活运用其语法差异,是每一位后端开发者和数据库管理员的必备技能。希望这篇结合实例的详解能帮助你构建起清晰的知识框架。




上一篇:Go 代码格式化实战:告别风格争论,用好 gofmt 与 VS Code
下一篇:OpenAI PostgreSQL架构实践:单主近50副本支撑8亿ChatGPT用户深度剖析
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-27 17:01 , Processed in 0.255180 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表