数据库复杂查询
基础
增删改查
进阶
聚合函数与分组查询
groud by分组
count(*)计数,以前面的为准,能够
以下方查询语句为例,查询count(*)实际上就是查找前面这个部门重复的人数,然后在通过分组返回数据
SELECT dept_id, COUNT(*) AS user_count
FROM users
GROUP BY dept_id;
那为什么要用groud by呢?
GROUP BY 决定“按哪个字段分组”,否则 SQL 不知道你要统计哪个部门。
那等于说用这个ground by进行分组,他会将你设置的字段将其合并在一起吗,比如我查找,部门名称,人数,性别,学号,然后用ground by 部门会是啥样的?
| id | name | dept_name | gender | student_no |
|---|---|---|---|---|
| 1 | 张三 | 数学 | 男 | 1001 |
| 2 | 李四 | 数学 | 女 | 1002 |
| 3 | 王五 | 语文 | 男 | 1003 |
| 4 | 赵六 | 数学 | 男 | 1004 |
SELECT dept_name, gender, COUNT(*) AS num_students
FROM students
GROUP BY dept_name;
会发生的错误,首先是count计算部门的数量之后,因为gender不是聚合函数,而且在group by里面也没有这个东西,所以会出现直接报错
但是如果
SELECT dept_name, gender, COUNT(*) AS num_students
FROM students
GROUP BY dept_name, gender;
这样的话就会按照dept——name以及gender进行排序
having(分组后的聚合函数需要用having而不是where)
WHERE 用于 行过滤(表中每一行)
HAVING 用于 分组过滤(GROUP BY 后的结果)
执行顺序(重要)
SELECT dept_name, COUNT(*) AS num_students
FROM students
GROUP BY dept_name
HAVING COUNT(*) > 2;
执行顺序:
-
FROM students→ 先拿到表的所有行 -
GROUP BY dept_name→ 按部门分组- 数学组:张三、李四
- 语文组:王五
-
COUNT(*)→ 计算每组行数- 数学=2,语文=1
-
HAVING COUNT(*) > 2→ 过滤- 数学=2 → 不满足 >2 → 被过滤
- 语文=1 → 不满足 → 被过滤
-
最终返回空(如果没有部门人数 >2)
子查询
“查询比自己所在部门平均工资高的员工”
先分别查出来部门的平均工资,然后比较员工工资和部门平均工资
先查找每个员工所在部门的平均工资,select avg(sale)from 表 where 部门id=员工id
排序与分页
SELECT * FROM employees ORDER BY salary DESC desc就是降序,不加就是升序 LIMIT 0, 10; -- 第 1 页 LIMIT 10, 10; -- 第 2 页
复杂条件查询
窗口函数
查询每个部门工资排名前 3 的员工
select 员工 from 表 where 部门id=员工id order by 工资,limit 3
查询最新的数据使用的窗口函数
查询最新的数据:ROW_NUMBER() 和 RANK()
通常可以使用 ROW_NUMBER() 窗口函数,它会为每个分组内的行按指定顺序排定一个唯一的排名,最新的数据会被标记为排名 1。
SELECT a.name, b.policy_name, b.purchase_date,
ROW_NUMBER() OVER (PARTITION BY a.id ORDER BY b.purchase_date DESC) AS rank
FROM customers a
JOIN policies b ON a.id = b.customer_id
WHERE rank = 1;
查询最近七天的数据:CURRENT_DATE 和 DATE_SUB
虽然窗口函数本身并不能直接提供基于日期范围的筛选,但你可以在查询中使用 日期函数(如 CURRENT_DATE)来限制数据范围,再结合窗口函数来分析。
SELECT a.name, b.policy_name, b.purchase_date,
ROW_NUMBER() OVER (PARTITION BY a.id ORDER BY b.purchase_date DESC) AS rank
FROM customers a
JOIN policies b ON a.id = b.customer_id
WHERE b.purchase_date >= DATE_SUB(CURRENT_DATE, INTERVAL 7 DAY);