Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > mysql dql查询

MySQL DQL从基础查询到实战优化全指南

作者:cyforkk

本文系统讲解MySQL DQL核心概念与规范,涵盖基础查询、条件筛选、聚合分析、分组排序及分页优化,强调避免SELECT*、合理使用索引、执行顺序理解,助你写出高效可读的查询语句,感兴趣的朋友跟随小编一起看看吧

MySQL DQL 完全指南:从基础查询到实战优化

DQL(数据查询语言)是 SQL 中最常用、最核心的部分 ——80% 的数据库操作都是 “查询”。无论是业务报表、数据分析还是页面展示,都离不开SELECT语句。但很多开发者写查询时只追求 “能查出结果”,却忽视了效率和可读性,导致 “查询慢”“逻辑乱” 等问题。本文从基础查询到复杂分组,再到执行顺序和规范,系统拆解 DQL 的核心知识点,帮你写出 “既正确又高效” 的查询语句。

一、DQL 核心概念与通用规范

1. 什么是 DQL?

DQL(Data Query Language)是用于从表中查询数据的 SQL 语句,核心命令只有一个:SELECT。它不修改数据,只返回结果集,是业务开发中使用频率最高的 SQL 类型。

2. 通用语法框架

所有查询语句都遵循以下基本结构(按执行顺序排列,而非书写顺序):

SELECT [DISTINCT] 字段列表  -- 5. 确定返回哪些字段
FROM 表名                  -- 1. 确定查询的表
[WHERE 条件]               -- 2. 筛选行(分组前)
[GROUP BY 分组字段]        -- 3. 按字段分组
[HAVING 分组条件]          -- 4. 筛选分组(分组后)
[ORDER BY 排序字段 [ASC/DESC]]  -- 6. 排序
[LIMIT 起始位置, 条数];    -- 7. 分页(限制返回条数)

3. 通用规范(提升可读性和效率)

二、基础查询:获取数据的第一步

基础查询是所有复杂查询的基础,核心是 “明确要查哪些字段”。

1. 语法与案例

(1)查询指定字段
-- 语法:SELECT 字段1, 字段2 FROM 表名;
SELECT emp_id, emp_name, salary FROM employee;  -- 查员工的ID、姓名、薪资
(2)查询所有字段(不推荐,仅临时调试用)
SELECT * FROM employee;  -- 查所有字段(生产环境禁止!)

问题:返回冗余字段(如无需展示的create_time),表加新字段后会自动返回,可能导致业务异常。

(3)去重查询(DISTINCT)
-- 语法:SELECT DISTINCT 字段 FROM 表名;  -- 去除字段重复值
SELECT DISTINCT dept_id FROM employee;  -- 查所有有员工的部门ID(去重)

注意:DISTINCT作用于其后所有字段(如DISTINCT a,b会同时去重 a 和 b 的组合)。

(4)别名查询(AS)

用别名简化字段名或表名,提升可读性:

-- 语法:字段/表名 [AS] 别名(AS可省略)
SELECT 
  emp_id AS 员工ID, 
  emp_name 姓名,  -- 省略AS
  salary * 12 年薪  -- 表达式也可加别名
FROM employee e;  -- 表别名e(后续可简写)

三、条件查询:筛选符合要求的数据

实际业务中很少查全表数据,而是按条件筛选(如 “查薪资> 10000 的员工”),WHERE子句是条件查询的核心。

1. 常用条件运算符

类型运算符 / 关键字说明
比较运算=、!=、>、<、>=、<=基本比较(如salary > 10000)
逻辑运算AND、OR、NOT多条件组合(如salary > 8000 AND dept_id=1)
范围查询BETWEEN … AND …在指定范围内(如age BETWEEN 20 AND 30)
集合查询IN (值1, 值2…)在指定集合中(如dept_id IN (1,2))
模糊查询LIKE匹配字符串(%通配任意字符,_通配单个字符)
空值查询IS NULL / IS NOT NULL判断是否为空(如dept_id IS NULL)

2. 实战案例

-- 案例1:查研发部(dept_id=1)薪资>10000的员工
SELECT emp_name, salary 
FROM employee 
WHERE dept_id = 1 AND salary > 10000;
-- 案例2:查年龄在25-35岁之间(包含25和35)的员工
SELECT emp_name, age 
FROM employee 
WHERE age BETWEEN 25 AND 35;  -- 等价于 age >=25 AND age <=35
-- 案例3:查部门ID为1、2、3的员工(用IN替代多个OR)
SELECT emp_name, dept_id 
FROM employee 
WHERE dept_id IN (1, 2, 3);  -- 比 dept_id=1 OR dept_id=2 更简洁
-- 案例4:查姓名以“张”开头的员工(模糊查询)
SELECT emp_name 
FROM employee 
WHERE emp_name LIKE '张%';  -- %匹配任意字符(如“张三”“张三丰”)
-- 案例5:查没有部门(dept_id为空)的员工
SELECT emp_name 
FROM employee 
WHERE dept_id IS NULL;  -- 注意:不能用 = NULL(NULL需用IS判断)

3. 条件查询规范

四、聚合函数:对数据做统计分析

聚合函数用于 “汇总数据”(如 “计算平均薪资”“统计员工总数”),常与GROUP BY配合使用。

1. 常用聚合函数

函数说明示例
COUNT()统计行数(非 NULL 值的数量)COUNT(emp_id) 统计有效员工数
SUM()求和(仅数值类型)SUM(salary) 计算总薪资
AVG()求平均值(仅数值类型)AVG(salary) 计算平均薪资
MAX()求最大值MAX(salary) 查最高薪资
MIN()求最小值MIN(hire_date) 查最早入职日期

2. 实战案例

-- 案例1:统计员工总数(COUNT(*)包含NULL,COUNT(字段)排除NULL)
SELECT 
  COUNT(*) AS 总记录数,  -- 包含所有行(包括字段为NULL的)
  COUNT(emp_id) AS 有效员工数  -- 仅统计emp_id非NULL的行(主键不会NULL)
FROM employee;
-- 案例2:计算研发部(dept_id=1)的薪资总和、平均值、最高值
SELECT 
  SUM(salary) AS 总薪资,
  AVG(salary) AS 平均薪资,
  MAX(salary) AS 最高薪资
FROM employee 
WHERE dept_id = 1;  -- 先筛选研发部,再聚合

3. 聚合函数注意事项

五、分组查询:按类别汇总数据

分组查询(GROUP BY)用于 “按某个字段分类统计”(如 “按部门统计员工数”),常与聚合函数配合。

1. 语法与案例

-- 基础语法:GROUP BY 分组字段 [HAVING 分组条件]
-- 案例1:按部门分组,统计每个部门的员工数和平均薪资
SELECT 
  dept_id AS 部门ID,
  COUNT(emp_id) AS 员工数,  -- 每个部门的员工数
  AVG(salary) AS 平均薪资   -- 每个部门的平均薪资
FROM employee 
GROUP BY dept_id;  -- 按部门ID分组
-- 案例2:分组后筛选(HAVING):平均薪资>9000的部门
SELECT 
  dept_id AS 部门ID,
  COUNT(emp_id) AS 员工数,
  AVG(salary) AS 平均薪资
FROM employee 
GROUP BY dept_id
HAVING 平均薪资 > 9000;  -- 筛选分组后的结果(用别名更简洁)

2. WHERE vs HAVING(核心区别)

子句作用时机能否用聚合函数典型场景
WHERE分组筛选行不能筛选单个字段(如dept_id=1)
HAVING分组筛选组筛选聚合结果(如AVG(salary)>9000)

示例对比

-- 先筛选2022年后入职的员工,再按部门分组统计平均薪资>8000的部门
SELECT 
  dept_id, 
  AVG(salary) AS 平均薪资
FROM employee 
WHERE hire_date >= '2022-01-01'  -- 分组前:只留2022年后入职的
GROUP BY dept_id
HAVING 平均薪资 > 8000;  -- 分组后:只留平均薪资超8000的部门

六、排序查询:按规则排列结果

查询结果默认无序,ORDER BY用于按指定字段排序(如 “按薪资从高到低排列”)。

1. 语法与案例

-- 基础语法:ORDER BY 字段1 [ASC/DESC], 字段2 [ASC/DESC]
-- ASC:升序(默认,可省略);DESC:降序
-- 案例1:按薪资降序排列(从高到低)
SELECT emp_name, salary 
FROM employee 
ORDER BY salary DESC;
-- 案例2:多字段排序:先按部门ID升序,再按薪资降序
SELECT emp_name, dept_id, salary 
FROM employee 
ORDER BY dept_id ASC, salary DESC;  -- 部门相同则比薪资

2. 排序规范

七、分页查询:限制返回结果条数

当数据量很大时(如 10 万条),需分页查询(如 “每页显示 10 条”),LIMIT是实现分页的核心。

1. 语法与案例

-- 语法:LIMIT 起始位置, 每页条数(起始位置从0开始)
-- 计算方式:第N页的起始位置 = (N-1) * 每页条数
-- 案例1:查询第1页数据(每页10条,起始位置0)
SELECT emp_id, emp_name 
FROM employee 
ORDER BY emp_id ASC  -- 分页必须先排序,保证顺序一致
LIMIT 0, 10;
-- 案例2:查询第2页数据(起始位置10,取10条)
SELECT emp_id, emp_name 
FROM employee 
ORDER BY emp_id ASC 
LIMIT 10, 10;

2. 分页规范

八、案例练习:综合查询实战

结合以上所有知识点,实现一个 “多条件统计 + 排序 + 分页” 的综合查询:

需求:查询研发部(dept_id=1)2022 年后入职的员工,按薪资降序排列,统计每个薪资段的人数,只看人数≥2 的薪资段,最后取第 1 页(每页 5 条)。

-- 分步拆解:
-- 1. 筛选研发部+2022年后入职(WHERE)
-- 2. 按薪资段分组(GROUP BY)
-- 3. 筛选人数≥2的组(HAVING)
-- 4. 按人数降序(ORDER BY)
-- 5. 分页取第1页(LIMIT)
SELECT 
  FLOOR(salary / 1000) * 1000 AS 薪资段,  -- 按1000为单位分组(如8000-8999)
  COUNT(emp_id) AS 人数
FROM employee 
WHERE dept_id = 1 AND hire_date >= '2022-01-01'
GROUP BY 薪资段
HAVING 人数 >= 2
ORDER BY 人数 DESC
LIMIT 0, 5;

九、DQL 执行顺序:理解查询的 “幕后流程”

很多人困惑 “为什么WHERE不能用聚合函数”“别名在哪个阶段生效”,答案在执行顺序里。DQL 各部分的执行顺序如下(与书写顺序不同):

举例说明

SELECT salary12 AS 年薪 FROM employee WHERE 年薪 > 100000 会报错 —— 因为WHERE在SELECT之前执行,此时 “年薪” 别名还未生成。正确写法是WHERE salary12 > 100000。

十、DQL 小结:核心要点与规范总览

1. 核心操作清单

操作类型关键字 / 语法核心作用注意事项
基础查询SELECT 字段 FROM 表获取指定字段数据禁止SELECT *,用别名简化
条件查询WHERE 条件筛选符合条件的行支持AND/OR/BETWEEN/LIKE等
聚合查询COUNT()/SUM()/AVG()等统计汇总数据忽略 NULL,WHERE中不能用
分组查询GROUP BY 字段 [HAVING 条件]按类别统计HAVING用于筛选分组结果
排序查询ORDER BY 字段 [ASC/DESC]按规则排列结果大表加索引,分页前必排序
分页查询LIMIT 起始位置, 条数限制返回条数,实现分页起始位置从 0 开始,需配合ORDER BY

2. 规范与最佳实践

DQL 是 SQL 的 “灵魂”,掌握它不仅能完成业务需求,更能通过优化查询提升系统性能。记住:写查询时多思考 “是否有更高效的方式”“别人能否看懂”,养成规范习惯,才能从 “会查” 变成 “查得好”。

到此这篇关于MySQL DQL 完全指南:从基础查询到实战优化的文章就介绍到这了,更多相关mysql dql内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文