
DQL语言:分组排序
更新: 2025/2/24 字数: 0 字 时长: 0 分钟
分组查询
分组查询:分组允许把数据分为多个逻辑组,以便能对每个组进行聚集计算。
分组是在SELECT语句的GROUP BY子句中建立的。
sql
/*
语法:
SELECT 分组函数,列(要求出现在GROUP BY的后面)
FROM 表
【WHERE 筛选条件】
GROUP BY 分组的列表
【HAVING 分组后的筛选】
注意:
查询列表必须是分组函数和GROUP BY后出现的字段
特点:
1、分组查询中的筛选条件分为两类
数据源 位置 关键字
分组前筛选 原始表 GROUP BY前面 WHERE
分组后筛选 分组后的结果集 GROUP BY后面 HAVING
2、分组函数做条件是放在HAVING子句中的。
3、能用分组前筛选的,优先考虑分组前筛选。
4、GROUP BY子句支持单个字段分组,多个字段分组(多个字段之间用逗号隔开没有顺序要求),表达式或函数(用的较少)
5、也可以添加排序(排序放在整个分组查询的最后)
6、GROUP BY子句中列出的每个列都必须是检索列或有效的表达式(但不能是聚集函数)。
7、除聚集计算语句外,SELECT语句中的每个列都必须在GROUP BY子句中给出。
8、在SELECT中使用表达式,则必须在GROUP BY子句中指定相同的表达式,并且不能使用别名。
9、GROUP BY子句必须出现在WHERE子句之后,ORDER BY子句之前。
10、如果分组列中具有NULL值,则NULL将作为一个分组返回。如果列中有多行NULL值,它们将分为一组。
*/
简单分组查询
类型 | 说明 |
---|---|
基本语法 | SELECT * FROM 表 GROUP BY 字段; |
示例 | SELECT * FROM star GROUP BY province; |
示例说明 | 按照province进行分组 |
sql
-- 查询每个工种的最高工资
SELECT
MAX(salary),
job_id
FROM
employees
GROUP BY
job_id;
类型 | 说明 |
---|---|
基本语法 | SELECT * FROM 表 GROUP BY 字段; |
示例 | SELECT count(*), province FROM star GROUP BY province; |
示例说明 | 对分组进行单独统计 |
sql
-- 查询每个位置上的部门个数
SELECT
COUNT(*),
location_id
FROM
departments
GROUP BY
location_id;
简单筛选条件
sql
-- 查询邮箱中包含a字符的,每个部门的平均工资
SELECT
AVG(salary),
department_id
FROM
employees
WHERE
email REGEXP 'a'
GROUP BY
department_id;
sql
-- 查询有奖金的每个领导手下员工的最高工资
SELECT
MAX(salary),
manager_id
FROM
employees
WHERE
commission_pct IS NOT NULL
GROUP BY
manager_id;
分组后查询
MySQL提供了 HAVING
子句。HAVING
非常类似于 WHERE
。唯一的差别是 WHERE
过滤行,而 HAVING
过滤分组。
类型 | 说明 |
---|---|
基本语法 | SELECT * FROM 表 GROUP BY 字段 HAVING 条件; |
示例 | SELECT count(province) as result , province FROM star GROUP BY province having result>2; |
示例说明 | 对province分组并统计总数,将分组结果中大于2的分组显示出来 |
?> 提示:HAVING
支持所有 WHERE
操作符,所学过的有关 WHERE
的所有这些技术和选项都适用于 HAVING
。
sql
-- 查询员工个数大于2的部门
SELECT
COUNT(*),
department_id
FROM
employees
GROUP BY
department_id
HAVING
COUNT(*) > 2;
sql
-- 查询每个工种有奖金的员工的最高工资大于12000的工种编号和最高工资
SELECT
MAX(salary),
job_id
FROM
employees
WHERE
commission_pct IS NOT NULL
GROUP BY
job_id
HAVING
MAX(salary) > 12000;
sql
-- 查询领导编号大于102的领导手下的最低工资大于5000的领导编号和最低工资
SELECT
MIN(salary),
manager_id
FROM
employees
WHERE
manager_id > 102
GROUP BY
manager_id
HAVING
MIN(salary) > 5000;
表达式函数
sql
-- 按员工姓名长度分组,查询每组员工个数,筛选处员工个数大于5的
SELECT
COUNT(*),
LENGTH(last_name)
FROM
employees
GROUP BY
LENGTH(last_name)
HAVING
COUNT(*) > 5;
多字段分组
sql
-- 查询每个部门每个工种的员工的平均工资
SELECT
AVG(salary),
department_id,
job_id
FROM
employees
GROUP BY
department_id,
job_id;
添加排序
sql
-- 查询每个部门每个工种的员工的平均工资大于10000,并按平均工资的高低显示
SELECT
AVG(salary),
department_id,
job_id
FROM
employees
GROUP BY
department_id,
job_id
HAVING
AVG(salary) > 10000
ORDER BY
AVG(salary) DESC;
排序查询
语法特点
sql
/*
语法:
SELECT 查询列表
FROM 表
【WHERE 筛选条件】
【GROUP BY 分组的列表】
ORDER BY 排序列表 【ASC|DESC】
特点:
1.ASC代表升序,DESC代表降序。如果都不写,默认代表升序。
2.OREDER BY子句中可以支持单个字段、多个字段、表达式、函数、别名
3.ORDER BY子句一般是放在查询语句的最后面,LIMIT子句除外。
*/
单列排序
升序检索:SELECT 字段名称 FROM 表名 ORDER BY 字段名称;
降序检索:SELECT 字段名称 FROM 表名 ORDER BY 字段名称 DESC;
类型 | 说明 |
---|---|
基本语法 | SELECT 字段 FROM 表 ORDER BY 字段 排序规则 LIMIT 数量; |
示例 | SELECT id, name, money FROM star ORDER BY money DESC LIMIT 5; |
示例说明 | 按照money来排序,显示前5个最有钱的记录 |
!> 注意:检索数据时,若没有排序,其结果是没有特定顺序的。
!> 注意:检索数据时,排序的字段可以是表中存在的任意字段。
sql
SELECT id, 公司名称 FROM 通用认证信息 ORDER BY id;
/*
# 以'id'字段升序,输出'id', '公司名称'字段。
+----+--------------+
| id | 公司名称 |
+----+--------------+
| 1 | 小白公司 |
| 2 | 小明公司 |
| 3 | 小红公司 |
+----+--------------+
3 rows in set (0.00 sec)
*/
SELECT id, 公司名称 FROM 通用认证信息 ORDER BY id DESC;
/*
# 以'id'字段降序,输出'id', '公司名称'字段。
+----+--------------+
| id | 公司名称 |
+----+--------------+
| 3 | 小红公司 |
| 2 | 小明公司 |
| 1 | 小白公司 |
+----+--------------+
3 rows in set (0.00 sec)
*/
多列排序
先字段1升序,后字段2升序检索:SELECT 字段名称 FROM 表名 ORDER BY 字段1, 字段2;
先字段2升序,后字段1升序检索:SELECT 字段名称 FROM 表名 ORDER BY 字段2, 字段1;
先字段1升序,后字段2降序检索:SELECT 字段名称 FROM 表名 ORDER BY 字段1, 字段2 DESC;
先字段1降序,后字段2降序检索:SELECT 字段名称 FROM 表名 ORDER BY 字段1 DESC, 字段2 DESC;
!> 注意:如果想在多个列上进行降序排序,必须对每个列指定DESC关键字。
sql
SELECT 公司名称,证书状态 FROM 通用认证信息 ORDER BY 公司名称,证书状态;
/*
# 以'公司名称'升序,再以'证书状态'升序,输出'公司名称','证书状态'字段
+--------------+--------------+
| 公司名称 | 证书状态 |
+--------------+--------------+
| 小明公司 | 过期 |
| 小白公司 | 有效 |
| 小红公司 | 过期 |
+--------------+--------------+
3 rows in set (0.00 sec)
*/
SELECT 公司名称,证书状态 FROM 通用认证信息 ORDER BY 证书状态,公司名称;
/*
# 以'证书状态'升序,再以'公司名称'升序,输出'公司名称','证书状态'字段
+--------------+--------------+
| 公司名称 | 证书状态 |
+--------------+--------------+
| 小白公司 | 有效 |
| 小明公司 | 过期 |
| 小红公司 | 过期 |
+--------------+--------------+
3 rows in set (0.00 sec)
*/
SELECT 公司名称,证书状态 FROM 通用认证信息 ORDER BY 证书状态,公司名称 DESC;
/*
# 以'证书状态'升序,再以'公司名称'降序,输出'公司名称','证书状态'字段
+--------------+--------------+
| 公司名称 | 证书状态 |
+--------------+--------------+
| 小白公司 | 有效 |
| 小红公司 | 过期 |
| 小明公司 | 过期 |
+--------------+--------------+
3 rows in set (0.00 sec)
*/
表达式排序
sql
-- 按年薪的高低降序显示员工的信息和年薪(没有年薪字段,需要表达式计算)
SELECT
*, salary * 12 * (1 + IFNULL(commission_pct, 0)) 年薪
FROM
employees
ORDER BY
salary * 12 * (1 + IFNULL(commission_pct, 0)) DESC;
-- ORDER BY 同样支持使用别名排序,上面语句重写为
SELECT
*, salary * 12 * (1 + IFNULL(commission_pct, 0)) 年薪
FROM
employees
ORDER BY
年薪 DESC;
函数排序
LENGTH(字段值)
:获取该字段的长度函数。
sql
-- 按姓名的长度降序显示员工的姓名和工资
SELECT
LENGTH(last_name) 姓名长度, last_name, salary
FROM
employees
ORDER BY
姓名长度 DESC;
分组排序总结
分组和排序
虽然 GROUP BY
和 ORDER BY
经常完成相同的工作,但它们是非常不同的。
ORDER BY | GROUP BY |
---|---|
排序 | 分组 |
任意列(包括非选择的列)都可以使用 | 只能使用选择列或表达式列,而且必须使用每个选择列表达式 |
不一定需要 | 与聚集函数一起使用列(或表达式),必须使用 |
SELECT子句顺序
回顾一下SELECT语句中子句的顺序:
子 句 | 说 明 | 必须使用 |
---|---|---|
SELECT | 要返回的列或表达式 | 是 |
FROM | 从中检索数据的表 | 仅在从表选择数据时使用 |
WHERE | 行级过滤 | 否 |
GROUP BY | 分组说明 | 仅在按组计算聚集时使用 |
HAVING | 组级过滤 | 否 |
ORDER BY | 输出排序顺序 | 否 |
LIMIT | 要检索的行数 | 否 |