SQL(Structured Query Language,结构化查询语言)是关系型数据库的标准操作语言,适用于 MySQL、Oracle、SQL Server、PostgreSQL 等主流数据库。本文将由浅入深,从基础语法、核心操作、进阶查询到高级特性、实战优化,全方位覆盖 SQL 常用语句,附带可直接运行的实战案例,零基础也能快速掌握。
前置说明:本文案例通用 90% 数据库,少量差异化语法会单独标注;所有案例基于通用数据表(用户表、订单表、商品表)演示,贴合实际业务。
一、SQL 基础认知与通用规范
1.1 SQL 分类
日常开发中核心使用 4 大类语句,也是本文重点讲解内容:
- DQL(数据查询语言) :核心
SELECT,用于查询数据(使用频率最高) - DML(数据操作语言) :
INSERT/UPDATE/DELETE,用于增改删数据 - DDL(数据定义语言) :
CREATE/ALTER/DROP,用于创建、修改、删除数据库、表、字段 - DCL(数据控制语言) :
GRANT/REVOKE,用于权限管理
1.2 通用语法规范
- SQL 语句不区分大小写,关键字建议大写(规范可读性)
- 每条语句以分号; 结尾
- 单行注释:
-- 注释内容;多行注释:/* 注释内容 */ - 字符串使用单引号
'内容',字段别名可使用双引号或反引号
二、SQL 基础操作
2.1 DDL 数据库与表操作
用于创建、修改、删除数据库和数据表,是建库建表的基础。
2.1.1 数据库操作
sql
-- 1. 创建数据库(指定编码,避免中文乱码)
CREATE DATABASE IF NOT EXISTS test_db DEFAULT CHARACTER SET utf8mb4;
-- 2. 查看所有数据库
SHOW DATABASES;
-- 3. 使用/切换数据库
USE test_db;
-- 4. 查看当前数据库
SELECT DATABASE();
-- 5. 删除数据库
DROP DATABASE IF EXISTS test_db;
2.1.2 数据表操作
sql
-- 1. 创建数据表(核心:字段名+数据类型+约束)
CREATE TABLE IF NOT EXISTS user (
id INT PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID,主键自增',
username VARCHAR(50) NOT NULL COMMENT '用户名',
age INT DEFAULT 18 COMMENT '年龄',
gender CHAR(1) COMMENT '性别',
create_time DATETIME DEFAULT NOW() COMMENT '创建时间',
is_delete TINYINT DEFAULT 0 COMMENT '删除标记:0未删除,1已删除'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
-- 2. 查看当前库所有表
SHOW TABLES;
-- 3. 查看表结构
DESC user;
-- 4. 修改表结构
-- 新增字段
ALTER TABLE user ADD COLUMN phone VARCHAR(11) COMMENT '手机号';
-- 修改字段类型
ALTER TABLE user MODIFY COLUMN age TINYINT;
-- 删除字段
ALTER TABLE user DROP COLUMN phone;
-- 修改表名
ALTER TABLE user RENAME TO user_info;
-- 5. 删除数据表
DROP TABLE IF EXISTS user_info;
2.2 DML 数据增删改操作
针对表中数据的新增、修改、删除,日常业务高频操作。
2.2.1 新增数据 INSERT
sql
-- 方式1:指定字段插入
INSERT INTO user(username, age, gender) VALUES ('张三', 22, '男');
-- 方式2:全字段插入(需和表字段顺序一致)
INSERT INTO user VALUES (NULL, '李四', 25, '女', NOW(), 0);
-- 方式3:批量插入(高效推荐)
INSERT INTO user(username, age, gender)
VALUES
('王五', 20, '男'),
('赵六', 23, '女');
2.2.2 修改数据 UPDATE
重要:修改必须加 WHERE 条件,否则更新全表!
sql
-- 单字段修改
UPDATE user SET age = 24 WHERE username = '张三';
-- 多字段修改
UPDATE user SET age = 26, gender = '男' WHERE id = 2;
-- 批量修改(匹配多条条件数据)
UPDATE user SET create_time = NOW() WHERE age > 20;
2.2.3 删除数据 DELETE
重要:删除必须加 WHERE 条件,否则清空全表!
sql
-- 条件删除单条/多条数据
DELETE FROM user WHERE id = 3;
-- 清空表数据(保留表结构,可回滚)
DELETE FROM user;
-- 快速清空表数据(不可回滚、自增主键重置,速度更快)
TRUNCATE TABLE user;
2.3 基础 DQL 查询语句
SELECT 查询是 SQL 重中之重,所有数据展示、统计、筛选都依赖此语句。
2.3.1 基础查询语法
sql
-- 1. 查询所有字段
SELECT * FROM user;
-- 2. 查询指定字段(推荐,避免冗余字段)
SELECT id, username, age FROM user;
-- 3. 字段起别名 AS(可省略)
SELECT id AS 用户ID, username 用户名, age 年龄 FROM user;
-- 4. 去重查询 DISTINCT
SELECT DISTINCT age FROM user;
-- 5. 限制查询条数 LIMIT(分页核心)
SELECT * FROM user LIMIT 2; -- 查询前2条
SELECT * FROM user LIMIT 1,2; -- 从第2条开始,查询2条(分页公式:LIMIT (page-1)*size, size)
2.3.2 条件查询 WHERE
用于筛选符合条件的数据,支持多种运算符:比较、逻辑、模糊、范围等。
sql
-- 比较运算符:=、!=、>、<、>=、<=
SELECT * FROM user WHERE age > 20;
SELECT * FROM user WHERE username != '张三';
-- 逻辑运算符:AND、OR、NOT
SELECT * FROM user WHERE age > 20 AND gender = '男';
SELECT * FROM user WHERE age < 18 OR age > 30;
-- 范围查询 BETWEEN ... AND ...
SELECT * FROM user WHERE age BETWEEN 20 AND 25;
-- 枚举查询 IN
SELECT * FROM user WHERE age IN (20,22,24);
-- 空值判断 IS NULL / IS NOT NULL
SELECT * FROM user WHERE phone IS NULL;
SELECT * FROM user WHERE phone IS NOT NULL;
2.3.3 模糊查询 LIKE
通配符:% 匹配任意多个字符,_ 匹配单个字符
sql
-- 用户名包含"张"
SELECT * FROM user WHERE username LIKE '%张%';
-- 用户名以"李"开头
SELECT * FROM user LIKE '李%';
-- 用户名第二个字为"五"
SELECT * FROM user WHERE username LIKE '_五%';
2.3.4 排序查询 ORDER BY
ASC 升序(默认),DESC 降序
sql
-- 年龄升序
SELECT * FROM user ORDER BY age ASC;
-- 年龄降序
SELECT * FROM user ORDER BY age DESC;
-- 多字段排序:年龄降序,同龄则ID升序
SELECT * FROM user ORDER BY age DESC, id ASC;
三、SQL 进阶核心操作
3.1 聚合函数与分组查询
聚合函数用于数据统计,分组查询用于分类统计,是报表、数据统计核心语法。
3.1.1 常用聚合函数
sql
-- COUNT:统计条数
SELECT COUNT(*) 总人数 FROM user; -- 统计所有数据
SELECT COUNT(age) 有效年龄人数 FROM user; -- 忽略NULL值
-- MAX/MIN:最大/最小值
SELECT MAX(age) 最大年龄, MIN(age) 最小年龄 FROM user;
-- SUM:求和
SELECT SUM(age) 年龄总和 FROM user;
-- AVG:平均值
SELECT AVG(age) 平均年龄 FROM user;
3.1.2 分组查询 GROUP BY
语法规则:SELECT 后的非聚合字段,必须出现在GROUP BY 后;HAVING 用于分组后筛选(替代 WHERE,WHERE 不能用于分组后)
sql
-- 按性别分组,统计每组人数
SELECT gender, COUNT(*) 人数 FROM user GROUP BY gender;
-- 按年龄分组,统计每组人数,筛选人数大于1的分组
SELECT age, COUNT(*) 人数 FROM user GROUP BY age HAVING 人数 > 1;
-- 多字段分组:按性别+年龄分组统计
SELECT gender, age, COUNT(*) 人数 FROM user GROUP BY gender, age;
3.2 多表联查
实际业务中数据分散在多张表,必须通过联查获取完整数据,核心 4 种连接方式。 演示表:用户表 user、订单表 order(user_id 关联用户 ID)
3.2.1 内连接 INNER JOIN
只查询两张表中匹配的数据,无匹配则不显示
sql
-- 查询用户及对应的订单信息
SELECT u.username, o.order_id, o.order_price
FROM user u
INNER JOIN `order` o
ON u.id = o.user_id;
3.2.2 左连接 LEFT JOIN
以左表为基准,左表数据全部展示,右表无匹配则显示 NULL(业务最常用)
sql
-- 查询所有用户,包含无订单的用户
SELECT u.username, o.order_id, o.order_price
FROM user u
LEFT JOIN `order` o
ON u.id = o.user_id;
3.2.3 右连接 RIGHT JOIN
以右表为基准,右表数据全部展示,左表无匹配则显示 NULL
sql
-- 查询所有订单,包含无对应用户的订单数据
SELECT u.username, o.order_id, o.order_price
FROM user u
RIGHT JOIN `order` o
ON u.id = o.user_id;
3.2.4 全连接 UNION
合并两张表所有数据,MySQL 无直接 FULL JOIN,通过 UNION 实现
sql
SELECT u.username, o.order_id FROM user u LEFT JOIN `order` o ON u.id = o.user_id
UNION
SELECT u.username, o.order_id FROM user u RIGHT JOIN `order` o ON u.id = o.user_id;
3.3 子查询
将一条 SQL 查询结果作为另一条 SQL 的参数,分为单行子查询、多行子查询、嵌套子查询。
3.3.1 单行子查询
sql
-- 查询年龄大于平均年龄的用户
SELECT * FROM user WHERE age > (SELECT AVG(age) FROM user);
3.3.2 多行子查询(IN/EXISTS)
sql
-- IN:匹配子查询返回的任意值
SELECT * FROM user WHERE id IN (SELECT user_id FROM `order`);
-- EXISTS:判断子查询是否有结果(效率高于IN)
SELECT * FROM user u WHERE EXISTS (SELECT 1 FROM `order` o WHERE o.user_id = u.id);
3.3.3 派生表子查询(FROM 后子查询)
sql
-- 先统计各年龄人数,再筛选人数大于1的记录
SELECT * FROM (SELECT age, COUNT(*) 人数 FROM user GROUP BY age) AS temp WHERE 人数 > 1;
四、SQL 高级特性
4.1 事务 Transaction
事务用于保证数据一致性,核心ACID 四大特性(原子性、一致性、隔离性、持久性),适用于转账、下单等多步数据操作场景。 MySQL InnoDB 引擎支持事务,MyISAM 不支持。
sql
-- 1. 开启事务
START TRANSACTION;
-- 2. 执行多条数据操作
UPDATE user SET age = 23 WHERE id = 1;
UPDATE user SET age = 21 WHERE id = 2;
-- 3. 提交事务(数据永久生效)
COMMIT;
-- 回滚事务(取消所有操作,数据恢复原状)
ROLLBACK;
4.2 索引操作
索引是提升查询效率的核心,合理建索引可大幅优化 SQL 性能。
sql
-- 1. 查看表索引
SHOW INDEX FROM user;
-- 2. 创建普通索引
CREATE INDEX idx_user_age ON user(age);
-- 3. 创建唯一索引(字段值唯一,允许NULL)
CREATE UNIQUE INDEX idx_user_phone ON user(phone);
-- 4. 创建联合索引
CREATE INDEX idx_user_age_gender ON user(age, gender);
-- 5. 删除索引
DROP INDEX idx_user_age ON user;
4.3 视图、存储过程、触发器
4.3.1 视图 VIEW
虚拟表,封装复杂查询语句,简化重复查询,不存储真实数据
sql
-- 创建视图
CREATE VIEW v_user_order AS
SELECT u.username, o.order_id, o.order_price FROM user u LEFT JOIN `order` o ON u.id = o.user_id;
-- 使用视图(直接查询虚拟表)
SELECT * FROM v_user_order;
-- 删除视图
DROP VIEW IF EXISTS v_user_order;
4.3.2 存储过程 PROCEDURE
封装一段 SQL 逻辑,可重复调用,支持参数传递,适合复杂批量操作
sql
-- 创建无参存储过程
DELIMITER // -- 修改语句结束符为//
CREATE PROCEDURE get_user_list()
BEGIN
SELECT * FROM user WHERE is_delete = 0;
END //
DELIMITER ; -- 恢复默认结束符
-- 调用存储过程
CALL get_user_list();
-- 删除存储过程
DROP PROCEDURE IF EXISTS get_user_list;
4.3.3 触发器 TRIGGER
监听表的增删改操作,触发自动执行指定 SQL 逻辑
sql
-- 创建触发器:新增用户后自动打印日志(简易示例)
DELIMITER //
CREATE TRIGGER trigger_user_add
AFTER INSERT ON user
FOR EACH ROW
BEGIN
INSERT INTO log_table(content) VALUES (CONCAT('新增用户:', NEW.username));
END //
DELIMITER ;
-- 删除触发器
DROP TRIGGER IF EXISTS trigger_user_add;
4.4 窗口函数(SQL 高级查询)
窗口函数是数据分析、排名、分组统计的高级用法,不压缩行数(区别于 GROUP BY),MySQL8.0+、Oracle、SQL Server 支持。
4.4.1 排名函数
sql
-- ROW_NUMBER():连续排名(1,2,3,4)
-- RANK():跳跃排名(1,2,2,4)
-- DENSE_RANK():密集排名(1,2,2,3)
SELECT
username,
age,
ROW_NUMBER() OVER(ORDER BY age DESC) 连续排名,
RANK() OVER(ORDER BY age DESC) 跳跃排名,
DENSE_RANK() OVER(ORDER BY age DESC) 密集排名
FROM user;
4.4.2 分区窗口函数
sql
-- 按性别分区,统计各性别年龄排名
SELECT
username, gender, age,
ROW_NUMBER() OVER(PARTITION BY gender ORDER BY age DESC) 性别内年龄排名
FROM user;
五、SQL 实战优化与避坑指南
5.1 高频错误避坑
- 禁止全表更新 / 删除:UPDATE/DELETE 必须加 WHERE 条件,生产环境建议先 SELECT 验证条件
- SELECT * 慎用:只查询业务需要的字段,减少 IO 消耗
- GROUP BY 规范:非聚合字段必须分组,避免语法报错或数据错乱
- 模糊查询前置 % 禁用:LIKE '% 张三 %'、LIKE '% 张三 ' 无法走索引,查询效率极低
5.2 SQL 性能优化核心
- WHERE 条件优先过滤数据,减少后续统计、联查的数据量
- 联查字段、WHERE 条件字段、排序字段合理建立索引
- 大表分页避免 LIMIT 100000,10,使用主键偏移分页优化
- 优先使用 EXISTS 替代 IN,大数据量下效率差距明显
- 避免在索引字段上使用函数、运算,会导致索引失效
六、常用 SQL 语句速查表
汇总日常开发高频语句,快速查阅使用:
- 基础查询:SELECT 字段 FROM 表 WHERE 条件 LIMIT 条数
- 统计查询:SELECT 聚合函数 FROM 表 GROUP BY 字段 HAVING 条件
- 多表联查:JOIN 表 ON 关联条件 + 筛选条件
- 数据操作:INSERT/UPDATE/DELETE 配合 WHERE 精准操作
- 性能优化:索引优化、避免全表扫描、合理使用窗口函数 / 子查询