SQL(Structured Query Language)是用于管理和操作关系型数据库的标准语言。本手册涵盖最常用的 SQL 语法,适用于 MySQL、PostgreSQL、SQLite、SQL Server 等主流数据库(部分语法可能略有差异,会特别注明)。


SQL 语句结构

  • SQL 语句以分号 ; 结尾。
  • 关键字不区分大小写,但习惯大写。
  • 标识符(表名、列名)在部分数据库中区分大小写(取决于配置)。
  • 注释:
    • 单行注释:-- 注释内容# 注释内容(MySQL)
    • 多行注释:/* 注释内容 */

数据查询语言 (DQL) - SELECT

用于从数据库中检索数据。

基本语法

1
2
3
4
5
6
7
SELECT [DISTINCT] 列1, 列2, ...
FROM 表名
[WHERE 条件]
[GROUP BY1, 列2, ...]
[HAVING 分组条件]
[ORDER BY1 [ASC|DESC], 列2 ...]
[LIMIT {行数 | 偏移量, 行数}];

常用子句

  • SELECT:指定要查询的列,* 表示所有列,DISTINCT 去重。
  • FROM:指定数据来源表。
  • WHERE:过滤行,支持 =, <>, >, <, >=, <=, BETWEEN, LIKE, IN, IS NULL 等运算符。
  • GROUP BY:按列分组,常与聚合函数一起使用。
  • HAVING:对分组结果进行过滤(类似 WHERE,但用于分组后)。
  • ORDER BY:排序,ASC 升序(默认),DESC 降序。
  • LIMIT / OFFSET:限制返回行数,实现分页。
    • MySQL / PostgreSQL / SQLite:LIMIT 10 OFFSET 20LIMIT 20, 10(MySQL 偏移, 行数)
    • SQL Server:OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY(需配合 ORDER BY

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 查询所有列
SELECT * FROM employees;

-- 查询特定列,去重
SELECT DISTINCT department_id FROM employees;

-- 带条件过滤
SELECT name, salary FROM employees WHERE salary > 5000;

-- 模糊匹配(% 任意字符,_ 单个字符)
SELECT name FROM employees WHERE name LIKE '张%';

-- 分组统计
SELECT department_id, COUNT(*) AS emp_count, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
HAVING AVG(salary) > 6000;

-- 排序 + 分页
SELECT name, hire_date FROM employees
ORDER BY hire_date DESC
LIMIT 10 OFFSET 0; -- 第一页,每页10条

数据操作语言 (DML)

用于操作表中的数据。

INSERT - 插入数据

1
2
3
4
5
6
7
8
9
10
11
12
-- 插入完整行(必须按顺序提供所有列值)
INSERT INTO 表名 VALUES (值1, 值2, ...);

-- 插入指定列
INSERT INTO 表名 (列1, 列2) VALUES (值1, 值2);

-- 插入多行
INSERT INTO 表名 (列1, 列2) VALUES (值1, 值2), (值3, 值4);

-- 从另一张表查询插入
INSERT INTO 表名 (列1, 列2)
SELECT 列A, 列B FROM 另一张表 WHERE 条件;

UPDATE - 更新数据

1
2
3
UPDATE 表名
SET1 = 新值1, 列2 = 新值2
WHERE 条件; -- 务必加 WHERE,否则更新全表

DELETE - 删除数据

1
2
DELETE FROM 表名
WHERE 条件; -- 务必加 WHERE,否则清空表

MERGE (UPSERT) - 合并插入/更新

不同数据库语法不同,以 PostgreSQL 为例:

1
2
INSERT INTO 表名 (列1, 列2) VALUES (值1, 值2)
ON CONFLICT (冲突列) DO UPDATE SET2 = excluded.列2;

MySQL:INSERT ... ON DUPLICATE KEY UPDATE ...


数据定义语言 (DDL)

用于定义数据库结构。

数据库操作

1
2
3
4
5
6
7
8
9
-- 创建数据库
CREATE DATABASE 数据库名;

-- 删除数据库
DROP DATABASE 数据库名;

-- 切换/使用数据库
USE 数据库名; -- MySQL
\c 数据库名; -- PostgreSQL

表操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
-- 创建表
CREATE TABLE 表名 (
列名1 数据类型 [约束],
列名2 数据类型 [约束],
...
);

-- 修改表
ALTER TABLE 表名
ADD COLUMN 列名 数据类型 [约束]; -- 添加列
ALTER TABLE 表名
DROP COLUMN 列名; -- 删除列
ALTER TABLE 表名
MODIFY COLUMN 列名 新数据类型; -- MySQL 修改列类型
ALTER TABLE 表名
ALTER COLUMN 列名 TYPE 新数据类型; -- PostgreSQL 修改列类型
ALTER TABLE 表名
RENAME COLUMN 旧列名 TO 新列名; -- 重命名列

-- 重命名表
ALTER TABLE 旧表名 RENAME TO 新表名;

-- 删除表
DROP TABLE 表名;

-- 清空表(删除所有行,但保留表结构)
TRUNCATE TABLE 表名;

索引

1
2
3
4
5
-- 创建索引
CREATE INDEX 索引名 ON 表名 (列1, 列2 ...);

-- 删除索引
DROP INDEX 索引名; -- 不同数据库语法有异,MySQL:DROP INDEX 索引名 ON 表名

视图

1
2
3
4
5
6
7
8
9
10
-- 创建视图
CREATE VIEW 视图名 AS
SELECT1, 列2 FROMWHERE 条件;

-- 修改视图
CREATE OR REPLACE VIEW 视图名 AS ... -- PostgreSQL / MySQL
ALTER VIEW 视图名 AS ... -- SQL Server

-- 删除视图
DROP VIEW 视图名;

数据控制语言 (DCL)

用于权限管理(通常由数据库管理员使用)。

1
2
3
4
5
-- 授予权限
GRANT SELECT, INSERT ON 数据库.表 TO '用户名'@'主机';

-- 撤销权限
REVOKE SELECT, INSERT ON 数据库.表 FROM '用户名'@'主机';

约束

用于保证数据的完整性和一致性。

约束类型 说明 示例
PRIMARY KEY 主键,唯一标识一行,自动包含 NOT NULL 和 UNIQUE id INT PRIMARY KEY
FOREIGN KEY 外键,引用另一张表的主键 dept_id INT REFERENCES departments(id)
UNIQUE 列值唯一 email VARCHAR(255) UNIQUE
NOT NULL 列值不能为空 name VARCHAR(100) NOT NULL
CHECK 检查列值满足条件 age INT CHECK (age >= 18)
DEFAULT 默认值 status VARCHAR(20) DEFAULT 'active'

可在创建表时定义,或之后添加:

1
2
3
ALTER TABLE 表名 ADD CONSTRAINT 约束名 PRIMARY KEY (列);
ALTER TABLE 表名 ADD CONSTRAINT 约束名 FOREIGN KEY (列) REFERENCES 其他表(列);
ALTER TABLE 表名 ADD CONSTRAINT 约束名 UNIQUE (列);

函数与操作符

聚合函数

  • COUNT(*) / COUNT(列):计数
  • SUM(列):求和
  • AVG(列):平均值
  • MAX(列) / MIN(列):最大值 / 最小值

字符串函数

函数 说明 示例
CONCAT(s1, s2) 连接字符串 CONCAT(first_name, ' ', last_name)
SUBSTRING(s, start, length) 截取子串 SUBSTRING('hello', 2, 3)ell
UPPER(s) / LOWER(s) 转大写 / 小写 UPPER(name)
LENGTH(s) 字符串长度 LENGTH('abc') → 3
TRIM(s) 去除首尾空格 TRIM(' abc ')
REPLACE(s, old, new) 替换 REPLACE('abc', 'b', 'x')axc

日期函数

  • CURRENT_DATE / CURDATE():当前日期
  • CURRENT_TIME / CURTIME():当前时间
  • NOW():当前日期和时间
  • DATE_PART('year', date) / YEAR(date):提取年份
  • DATEADD / DATE_ADD:日期加减(不同数据库语法不同)
  • DATEDIFF:日期差

数学函数

  • ABS(x):绝对值
  • ROUND(x, d):四舍五入
  • CEIL(x) / FLOOR(x):向上 / 向下取整
  • MOD(x, y):取余

条件表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
-- CASE 表达式
SELECT
name,
CASE
WHEN age < 18 THEN '未成年'
WHEN age BETWEEN 18 AND 60 THEN '成年'
ELSE '老年'
END AS age_group
FROM users;

-- COALESCE 返回第一个非 NULL 值
SELECT COALESCE(phone, email, '无联系方式') FROM contacts;

-- NULLIF 如果两值相等则返回 NULL
SELECT NULLIF(status, 'inactive') FROM orders;

连接 (JOIN)

用于从多张表联合查询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
-- 内连接:只返回匹配的行
SELECT *
FROM 表A
INNER JOIN 表B ON 表A.列 = 表B.列;

-- 左连接:返回左表所有行,右表无匹配则为 NULL
SELECT *
FROM 表A
LEFT JOIN 表B ON 表A.列 = 表B.列;

-- 右连接:返回右表所有行
SELECT *
FROM 表A
RIGHT JOIN 表B ON 表A.列 = 表B.列;

-- 全连接:返回所有行(MySQL 不支持,可用 UNION 模拟)
SELECT *
FROM 表A
FULL OUTER JOIN 表B ON 表A.列 = 表B.列;

-- 交叉连接:笛卡尔积
SELECT *
FROM 表A
CROSS JOIN 表B;

-- 自连接:将表与自身连接
SELECT e1.name AS 员工, e2.name AS 经理
FROM employees e1
LEFT JOIN employees e2 ON e1.manager_id = e2.id;

子查询

嵌套在另一个查询中的查询。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
-- 标量子查询(返回单个值)
SELECT name, salary
FROM employees
WHERE salary > (SELECT AVG(salary) FROM employees);

-- 行子查询(返回一行)
SELECT * FROM employees
WHERE (department_id, salary) = (SELECT department_id, MAX(salary) FROM employees);

-- 表子查询(作为临时表)
SELECT dept_name, avg_salary
FROM (SELECT department_id, AVG(salary) AS avg_salary FROM employees GROUP BY department_id) AS dept_avg
JOIN departments ON dept_avg.department_id = departments.id;

-- 关联子查询(引用外层表)
SELECT e1.name, e1.salary
FROM employees e1
WHERE salary > (SELECT AVG(salary) FROM employees e2 WHERE e2.department_id = e1.department_id);

-- EXISTS / NOT EXISTS
SELECT d.name
FROM departments d
WHERE EXISTS (SELECT 1 FROM employees e WHERE e.department_id = d.id);

-- IN / NOT IN
SELECT name FROM employees WHERE department_id IN (SELECT id FROM departments WHERE location = '北京');

-- ANY / ALL
SELECT name, salary FROM employees
WHERE salary > ANY (SELECT salary FROM employees WHERE department_id = 10); -- 大于子查询中任意一个值

集合操作

合并多个查询的结果。

  • UNION:合并并去重
  • UNION ALL:合并保留重复行
  • INTERSECT:交集(MySQL 不支持)
  • EXCEPT / MINUS:差集(MySQL 不支持)
1
2
3
4
5
SELECT name FROM customers
UNION
SELECT name FROM employees;

-- 必须列数相同,数据类型兼容

事务

保证一组操作要么全部成功,要么全部失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 开始事务
BEGIN; -- 或 START TRANSACTION;

-- 执行操作
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- 提交事务
COMMIT;

-- 回滚事务(撤销未提交的更改)
ROLLBACK;

-- 设置保存点
SAVEPOINT sp1;
ROLLBACK TO SAVEPOINT sp1;

事务需满足 ACID 特性(原子性、一致性、隔离性、持久性)。

常见数据库差异提示

  • 字符串连接
    • MySQL:CONCAT('a', 'b')'a' 'b'(空格)
    • PostgreSQL / SQLite:'a' || 'b'
    • SQL Server:'a' + 'b'
  • 分页
    • MySQL / PostgreSQL / SQLite:LIMIT 10 OFFSET 20
    • SQL Server / Oracle 12c+:OFFSET 20 ROWS FETCH NEXT 10 ROWS ONLY
  • 自增列
    • MySQL:AUTO_INCREMENT
    • PostgreSQL:SERIALIDENTITY
    • SQL Server:IDENTITY(1,1)
  • 获取当前日期时间
    • MySQL:NOW(), CURDATE()
    • PostgreSQL:CURRENT_TIMESTAMP, CURRENT_DATE
    • SQL Server:GETDATE()

综合示例

假设有两张表:employees(员工)和 departments(部门)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
-- 创建表
CREATE TABLE departments (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL UNIQUE
);

CREATE TABLE employees (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
salary DECIMAL(10,2),
hire_date DATE,
department_id INT,
FOREIGN KEY (department_id) REFERENCES departments(id)
);

-- 插入数据
INSERT INTO departments (name) VALUES ('研发部'), ('市场部'), ('销售部');
INSERT INTO employees (name, salary, hire_date, department_id) VALUES
('张三', 8000, '2020-01-15', 1),
('李四', 7500, '2019-03-20', 2),
('王五', 9000, '2021-06-10', 1),
('赵六', 7200, '2022-11-05', 3);

-- 查询每个部门的平均薪资,显示部门名称
SELECT d.name AS 部门名称, AVG(e.salary) AS 平均薪资
FROM employees e
JOIN departments d ON e.department_id = d.id
GROUP BY d.name
HAVING AVG(e.salary) > 7500;

-- 查找薪资高于公司平均薪资的员工及其部门
SELECT e.name, e.salary, d.name AS department
FROM employees e
JOIN departments d ON e.department_id = d.id
WHERE e.salary > (SELECT AVG(salary) FROM employees);

-- 更新薪资(为研发部员工加薪10%)
UPDATE employees
SET salary = salary * 1.1
WHERE department_id = (SELECT id FROM departments WHERE name = '研发部');

-- 删除没有员工的部门
DELETE FROM departments
WHERE id NOT IN (SELECT DISTINCT department_id FROM employees WHERE department_id IS NOT NULL);