1、CASE WHEN函数语句多条件
-- 请在此处输入 SQL
select name,
case when (age>60) then '老同学'
when (age>20) then '年轻'
else '小同学'
end as age_level
from student
order by name
2、函数 - 时间函数
- DATE:获取当前日期
- DATETIME:获取当前日期时间
- TIME:获取当前时间
-- 获取当前日期
SELECT DATE() AS date();
-- 获取当前时间
SELECT TIME() AS time();
-- 获取当前日期时间
SELECT DATETIME() AS datetime();
date() | time() | datetime() |
---|---|---|
2023-08-01 | 14:30:00 | 2023-08-01 14:30:00 |
3、函数 - 字符串处理
字符串进行各种操作,如转换大(upper)小(lower)写、计算字符串长度(length)以及搜索和替换子字符串等。
4、聚合函数:汇总计算
- COUNT():计算指定列的行数或非空值的数量。
- SUM():计算指定列的数值之和。
- AVG():计算指定列的数值平均值。
- MAX():找出指定列的最大值。
- MIN():找出指定列的最小值。
5、分组聚合 - 多字段分组
要查询使用多字段分组查询表中 每个客户 购买的 每种商品 的总金额,相当于按照客户编号和商品编号分组:
-- 查询每个用户购买的每种商品的总金额,按照客户编号和商品编号分组
SELECT customer_id, product_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id, product_id;
6、关联查询
6.1 (cross)join或者 ,------笛卡尔积
方式1(,):
SELECT e.emp_name, e.salary, e.department, d.manager
FROM
employees e,departments d;
方式2(join):
SELECT e.emp_name, e.salary, e.department, d.manager
FROM
employees e JOIN departments d;
方式3(cross join):
SELECT e.emp_name, e.salary, e.department, d.manager
FROM
employees e CROSS JOIN departments d;
员工表 employees
:emp_id
(员工编号)、emp_name
(员工姓名)、department
(所属部门)、salary
(工资)。数据如下:
emp_id | emp_name | department | salary |
---|---|---|---|
1 | 小明 | 技术部 | 5000 |
2 | 鸡哥 | 财务部 | 6000 |
3 | 李华 | 销售部 | 4500 |
部门表 departments
:department
(部门名称)、manager
(部门经理)、location
(所在地)。数据如下:
department | manager | location |
---|---|---|
技术部 | 张三 | 上海 |
财务部 | 李四 | 北京 |
销售部 | 王五 | 广州 |
查询结果:
emp_name | salary | department | manager |
---|---|---|---|
小明 | 5000 | 技术部 | 张三 |
小明 | 5000 | 财务部 | 李四 |
小明 | 5000 | 销售部 | 王五 |
鸡哥 | 6000 | 技术部 | 张三 |
鸡哥 | 6000 | 财务部 | 李四 |
鸡哥 | 6000 | 销售部 | 王五 |
李华 | 4500 | 技术部 | 张三 |
李华 | 4500 | 财务部 | 李四 |
李华 | 4500 | 销售部 | 王五 |
6.2 (inner)join on
方式1
SELECT e.emp_name, e.salary, e.department, d.manager
FROM employees e
JOIN departments d ON e.department = d.department;
方式2
SELECT e.emp_name, e.salary, e.department, d.manager
FROM employees e
INNER JOIN departments d ON e.department = d.department;
员工表 employees
:emp_id
(员工编号)、emp_name
(员工姓名)、department
(所属部门)、salary
(工资)。数据如下:
emp_id | emp_name | department | salary |
---|---|---|---|
1 | 小明 | 技术部 | 5000 |
2 | 鸡哥 | 财务部 | 6000 |
3 | 李华 | 销售部 | 4500 |
部门表 departments
:department
(部门名称)、manager
(部门经理)、location
(所在地)。数据如下:
department | manager | location |
---|---|---|
技术部 | 张三 | 上海 |
财务部 | 李四 | 北京 |
销售部 | 王五 | 广州 |
摸鱼部 | 赵二 | 吐鲁番 |
查询结果如下:
emp_name | salary | department | manager |
---|---|---|---|
小明 | 5000 | 技术部 | 张三 |
鸡哥 | 6000 | 财务部 | 李四 |
李华 | 4500 | 销售部 | 王五 |
6.3 OUTER JOIN 中,包括 LEFT OUTER JOIN 和 RIGHT OUTER JOIN
left join
员工表 employees
:emp_id
(员工编号)、emp_name
(员工姓名)、department
(所属部门)、salary
(工资)。数据如下:
emp_id | emp_name | department | salary |
---|---|---|---|
1 | 小明 | 技术部 | 5000 |
2 | 鸡哥 | 财务部 | 6000 |
3 | 李华 | 销售部 | 4500 |
部门表 departments
:department
(部门名称)、manager
(部门经理)、location
(所在地)。数据如下:
department | manager | location |
---|---|---|
技术部 | 张三 | 上海 |
财务部 | 李四 | 北京 |
人事部 | 王五 | 广州 |
摸鱼部 | 赵二 | 吐鲁番 |
SELECT e.emp_name, e.salary, e.department, d.manager
FROM
employees e LEFT JOIN departments d
ON e.department = d.department;
查询结果:
emp_name | salary | department | manager |
---|---|---|---|
小明 | 5000 | 技术部 | 张三 |
鸡哥 | 6000 | 财务部 | 李四 |
李华 | 4500 | 销售部 | NULL |
right join
员工表 employees
:emp_id
(员工编号)、emp_name
(员工姓名)、department
(所属部门)、salary
(工资)。数据如下:
emp_id | emp_name | department | salary |
---|---|---|---|
1 | 小明 | 技术部 | 5000 |
2 | 鸡哥 | 财务部 | 6000 |
3 | 李华 | 销售部 | 4500 |
部门表 departments
:department
(部门名称)、manager
(部门经理)、location
(所在地)。数据如下:
department | manager | location |
---|---|---|
技术部 | 张三 | 上海 |
财务部 | 李四 | 北京 |
人事部 | 王五 | 广州 |
摸鱼部 | 赵二 | 吐鲁番 |
SELECT e.emp_name, e.salary, e.department, d.manager
FROM
employees e RIGHT JOIN departments d
ON e.department = d.department;
查询结果:
7、查询进阶 - 组合查询:UNION 和 UNION ALL
table1 表:
emp_id | name | age | department |
---|---|---|---|
101 | Alice | 25 | HR |
102 | Bob | 28 | Finance |
103 | Charlie | 22 | IT |
table2 表:
emp_id | name | age | department |
---|---|---|---|
101 | Alice | 25 | HR |
201 | David | 27 | Finance |
202 | Eve | 24 | HR |
203 | Frank | 26 | IT |
7.1 UNION 操作的结果,去除了重复的行(名称为 Alice):
SELECT name, age, department
FROM table1
UNION
SELECT name, age, department
FROM table2;
name | age | department |
---|---|---|
Alice | 25 | HR |
Bob | 28 | Finance |
Charlie | 22 | IT |
David | 27 | Finance |
Eve | 24 | HR |
Frank | 26 | IT |
7.2 UNION ALL 操作,保留了重复的行::
SELECT name, age, department
FROM table1
UNION
SELECT name, age, department
FROM table2;
name | age | department |
---|---|---|
Alice | 25 | HR |
Bob | 28 | Finance |
Charlie | 22 | IT |
Alice | 25 | HR |
David | 27 | Finance |
Eve | 24 | HR |
Frank | 26 | IT |
8、开窗函数
开窗函数是一种强大的查询工具,它允许我们在查询中进行对分组数据进行计算、 同时保留原始行的详细信息 。
8.1 sum over(分组统计)
SUM(计算字段名) OVER (PARTITION BY 分组字段名)
订单表 orders
,表格数据如下:
order_id | customer_id | order_date | total_amount |
---|---|---|---|
1 | 101 | 2023-01-01 | 200 |
2 | 102 | 2023-01-05 | 350 |
3 | 101 | 2023-01-10 | 120 |
4 | 103 | 2023-01-15 | 500 |
计算每个客户的订单总金额,并显示每个订单的详细信息。
SELECT
order_id,
customer_id,
order_date,
total_amount,
SUM(total_amount) OVER (PARTITION BY customer_id) AS customer_total_amount
FROM
orders;
查询结果:
order_id | customer_id | order_date | total_amount | customer_total_amount |
---|---|---|---|---|
1 | 101 | 2023-01-01 | 200 | 320 |
3 | 101 | 2023-01-10 | 120 | 320 |
2 | 102 | 2023-01-05 | 350 | 350 |
4 | 103 | 2023-01-15 | 500 | 500 |
在上面的示例中,我们使用开窗函数 SUM 来计算每个客户的订单总金额(customer_total_amount),并使用 PARTITION BY 子句按照customer_id 进行分组。从前两行可以看到,开窗函数保留了原始订单的详细信息,同时计算了每个客户的订单总金额。
8.2 sum over order by(同组内数据的 累加求和 )
SUM(计算字段名) OVER (PARTITION BY 分组字段名 ORDER BY 排序字段 排序规则)
orders
,表格数据如下:
order_id | customer_id | order_date | total_amount |
---|---|---|---|
1 | 101 | 2023-01-01 | 200 |
2 | 102 | 2023-01-05 | 350 |
3 | 101 | 2023-01-10 | 120 |
4 | 103 | 2023-01-15 | 500 |
计算每个客户的历史订单累计金额,并显示每个订单的详细信息。
SELECT
order_id,
customer_id,
order_date,
total_amount,
SUM(total_amount) OVER (PARTITION BY customer_id ORDER BY order_date ASC) AS cumulative_total_amount
FROM
orders;
结果将是:
order_id | customer_id | order_date | total_amount | cumulative_total_amount |
---|---|---|---|---|
1 | 101 | 2023-01-01 | 200 | 200 |
3 | 101 | 2023-01-10 | 120 | 320 |
2 | 102 | 2023-01-05 | 350 | 350 |
4 | 103 | 2023-01-15 | 500 | 500 |
在上面的示例中,我们使用开窗函数 SUM 来计算每个客户的历史订单累计金额(cumulative_total_amount),并使用 PARTITION BY 子句按照 customer_id 进行分组,并使用 ORDER BY 子句按照 order_date 进行排序。从结果的前两行可以看到,开窗函数保留了原始订单的详细信息,同时计算了每个客户的历史订单累计金额;相比于只用 sum over,同组内的累加列名称
8.3 rank(用于对查询结果集中的行进行 排名)
⚠️ 当存在并列(相同排序值)时,Rank 会跳过后续排名,并保留相同的排名。
表 orders
,表格数据如下:
order_id | customer_id | order_date | total_amount |
---|---|---|---|
1 | 101 | 2023-01-01 | 200 |
2 | 102 | 2023-01-05 | 350 |
3 | 101 | 2023-01-10 | 120 |
4 | 103 | 2023-01-15 | 500 |
为每个客户的订单按照订单金额降序排名,并显示每个订单的详细信息。
SELECT
order_id,
customer_id,
order_date,
total_amount,
RANK() OVER (PARTITION BY customer_id ORDER BY total_amount DESC) AS customer_rank
FROM
orders;
查询结果:
order_id | customer_id | order_date | total_amount | customer_rank |
---|---|---|---|---|
1 | 101 | 2023-01-01 | 200 | 1 |
3 | 101 | 2023-01-10 | 120 | 2 |
2 | 102 | 2023-01-05 | 350 | 1 |
4 | 103 | 2023-01-15 | 500 | 1 |
在上面的示例中,我们使用开窗函数 RANK 来为每个客户的订单按照订单金额降序排名(customer_rank),并使用 PARTITION BY 子句按照 customer_id 进行分组,并使用 ORDER BY 子句按照 total_amount 从大到小进行排序。
可以看到,开窗函数保留了原始订单的详细信息,同时计算了每个客户的订单金额排名。
8.4 row_number(为查询结果集中的每一行 分配唯一连续排名)
表 orders
,表格数据如下:
order_id | customer_id | order_date | total_amount |
---|---|---|---|
1 | 101 | 2023-01-01 | 200 |
2 | 102 | 2023-01-05 | 350 |
3 | 101 | 2023-01-10 | 120 |
4 | 103 | 2023-01-15 | 500 |
为每个客户的订单按照订单金额降序排列,并且分配一个 row_number 编号。
SELECT
order_id,
customer_id,
order_date,
total_amount,
ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY total_amount DESC) AS row_number
FROM
orders;
结果将是:
order_id | customer_id | order_date | total_amount | row_number |
---|---|---|---|---|
4 | 103 | 2023-01-15 | 500 | 1 |
2 | 102 | 2023-01-05 | 350 | 1 |
1 | 101 | 2023-01-01 | 200 | 1 |
3 | 101 | 2023-01-10 | 120 | 2 |
在上面的示例中,我们使用开窗函数 ROW_NUMBER 为每个客户的订单按照订单金额降序排列,并为每个订单分配了一个编号(row_number),并使用 PARTITION BY 子句按照 customer_id 进行分组,并使用 ORDER BY 子句按照 total_amount 进行排序。
8.5 lag/lead(获取在当前行之前或之后的行的值)
💡 比较相邻行数据或进行时间序列分析时非常有用
LAG(取值的列名, 向⬆️偏移的行数, 指定当没有前一行时的默认值) OVER (PARTITION BY 分组字段名 ORDER BY 排序字段名)
LEAD(取值的列名, 向⬇️偏移的行数, 指定当没有前一行时的默认值) OVER (PARTITION BY 分组字段名 ORDER BY 排序字段名)
学生成绩表scores
,其中包含学生的成绩和考试日期:
student_id | exam_date | score |
---|---|---|
101 | 2023-01-01 | 85 |
101 | 2023-01-05 | 78 |
101 | 2023-01-10 | 92 |
101 | 2023-01-15 | 80 |
查询每个学生的考试日期和上一次考试的成绩,以及下一次考试的成绩。
SELECT
student_id,
exam_date,
score,
LAG(score, 1, NULL) OVER (PARTITION BY student_id ORDER BY exam_date) AS previous_score,
LEAD(score, 1, NULL) OVER (PARTITION BY student_id ORDER BY exam_date) AS next_score
FROM
scores;
结果将是:
student_id | exam_date | score | previous_score | next_score |
---|---|---|---|---|
101 | 2023-01-01 | 85 | NULL | 78 |
101 | 2023-01-05 | 78 | 85 | 92 |
101 | 2023-01-10 | 92 | 78 | 80 |
101 | 2023-01-15 | 80 | 92 | NULL |