单表查询
常量查询
让我们来看一个具体的 SQL 代码和结果示例,假设有一张名为 orders
的数据表,它存储了订单信息,包括订单编号(order_id)、商品单价(unit_price)、购买数量(quantity)等:
数据表orders
:
order_id | unit_price | quantity |
---|---|---|
1001 | 10.00 | 5 |
1002 | 20.00 | 3 |
1003 | 15.00 | 2 |
1004 | 25.00 | 4 |
现在,我们需要计算每个订单的总金额(total_amount),即商品单价(unit_price)乘以购买数量(quantity)。
SQL 查询语句如下:
select order_id, unit_price, quantity, unit_price * quantity as total_amount from orders;
between and 运算符
使用 “BETWEEN” 运算符筛选出年龄在 25 到 30 之间的员工:
-- SQL查询语句
select name, age, salary from employees where age between 25 and 30;
判断是否为空值
在数据库中,有时候数据表的某些字段可能没有值,即为空值(NULL)。
空值表示该字段的值是未知的、不存在的或者没有被填写的。在SQL查询中,我们可以使用 “IS NULL” 和 “IS NOT NULL” 来判断字段是否为空值或非空值
模糊查询
模糊查询是一种特殊的条件查询,它允许我们根据模式匹配来查找符合特定条件的数据,可以使用 LIKE 关键字实现模糊查询。
在 LIKE 模糊查询中,我们使用通配符来代表零个或多个字符,从而能够快速地找到匹配的数据。
有如下 2 种通配符:
- 百分号(%):表示任意长度的任意字符序列。
- 下划线(_ ):表示任意单个字符。
同理,可以使用 not like
来查询不包含某关键字的信息
逻辑运算符
逻辑运算是一种在条件查询中使用的运算符,它允许我们结合多个条件来过滤出符合特定条件的数据。
在逻辑运算中,常用的运算符有:
- AND:表示逻辑与,要求同时满足多个条件,才返回 true。
- OR:表示逻辑或,要求满足其中任意一个条件,就返回 true。
- NOT:表示逻辑非,用于否定一个条件(本来是 true,用了 not 后转为 false)
去重
在数据表中,可能存在重复的数据记录,但如果我们想要过滤掉重复的记录,只保留不同的记录,就要使用 SQL 的去重功能。
在 SQL 中,我们可以使用 DISTINCT
关键字来实现去重操作。
-- SQL 查询语句
select distinct class_id from students;
除了按照单字段去重外,DISTINCT
关键字还支持根据多个字段的组合来进行去重操作,确保多个字段的组合是唯一的。
示例语法如下:
distinct 字段1, 字段2, 字段3, ...
排序
在查询数据时,我们有时希望对结果按照某个字段的值进行排序,以便更好地查看数据。
在 SQL 中,我们可以使用 ORDER BY
关键字来实现排序操作。ORDER BY
后面跟上需要排序的字段,可以选择升序(ASC)或降序(DESC)排列。
-- SQL 查询语句 1
select name, age from students order by age asc;-- SQL 查询语句 2
select name, score from students order by score desc;
在排序的基础上,我们还可以根据多个字段的值进行排序。当第一个字段的值相同时,再按照第二个字段的值进行排序,以此类推。
示例语法如下:
order by 字段1 [升序/降序], 字段2 [升序/降序], ...
截断和偏移
在 SQL 中,我们使用 LIMIT
关键字来实现数据的截断和偏移。
截断和偏移的一个典型的应用场景是分页,即网站内容很多时,用户可以根据页号每次只看部分数据。
-- LIMIT 后只跟一个整数,表示要截断的数据条数(一次获取几条)
select task_name, due_date from tasks limit 2;-- LIMIT 后跟 2 个整数,依次表示从第几条数据开始、一次获取几条
select task_name, due_date from tasks limit 2, 2;
查询语句 2 结果,从下标为 2(第 3 条)数据的位置开始获取 2 条数据:
注:左闭的,但是是下标的索引值
条件分支
使用 case when
可以在查询结果中根据特定的条件动态生成新的列或对现有的列进行转换。
示例 SQL 如下:
SELECTname,CASE WHEN (name = '鸡哥') THEN '会' ELSE '不会' END AS can_rap
FROMstudent;
查询结果:
name | can_rap |
---|---|
小明 | 不会 |
鸡哥 | 会 |
李华 | 不会 |
王五 | 不会 |
case when
支持同时指定多个分支,示例语法如下:
CASE WHEN (条件1) THEN 结果1WHEN (条件2) THEN 结果2...ELSE 其他结果 END
select name,
case when(age > 60) then "老同学"when(age > 20) then "年轻"else "小同学" end as age_level
from student order by name asc
注:case 返回的是一个字段
时间函数
常用的时间函数有:
- DATE:获取当前日期
- DATETIME:获取当前日期时间
- TIME:获取当前时间
示例
假设有一个订单表 orders
,包含以下字段:order_id
(订单号)、order_date
(下单日期)、order_time
(下单时间)。数据如下:
order_id | order_date | order_time |
---|---|---|
1 | 2023-08-01 | 12:30:45 |
2 | 2023-08-01 | 14:20:10 |
3 | 2023-08-02 | 09:15:00 |
4 | 2023-08-02 | 18:05:30 |
使用时间函数获取当前日期、当前日期时间和当前时间:
-- 获取当前日期
SELECT DATE() AS current_date;-- 获取当前日期时间
SELECT DATETIME() AS current_datetime;-- 获取当前时间
SELECT TIME() AS current_time;
查询结果:
为了方便对比,放到同一个表格
current_date | current_datetime | current_time |
---|---|---|
2023-08-01 | 2023-08-01 14:30:00 | 14:30:00 |
注意,这里的日期、日期时间和时间将根据当前的系统时间来生成,实际运行结果可能会因为当前时间而不同。
字符串
在 SQL 中,字符串处理是一类用于处理文本数据的函数。它们允许我们对字符串进行各种操作,如转换大小写、计算字符串长度以及搜索和替换子字符串等。字符串处理函数可以帮助我们在数据库中对字符串进行加工和转换,从而满足不同的需求。
- upper(xxx)
- length(xxx)
- lower(xxx)
聚合函数
在 SQL 中,聚合函数是一类用于对数据集进行 汇总计算 的特殊函数。它们可以对一组数据执行诸如计数、求和、平均值、最大值和最小值等操作。聚合函数通常在 SELECT 语句中配合 GROUP BY 子句使用,用于对分组后的数据进行汇总分析。
常见的聚合函数包括:
- COUNT:计算指定列的行数或非空值的数量。
- SUM:计算指定列的数值之和。
- AVG:计算指定列的数值平均值。
- MAX:找出指定列的最大值。
- MIN:找出指定列的最小值。
示例
假设有一个订单表 orders
,包含以下字段:order_id
(订单号)、customer_id
(客户编号)、amount
(订单金额)。数据如下:
order_id | customer_id | amount |
---|---|---|
1 | A001 | 100 |
2 | A002 | 200 |
3 | A001 | 150 |
4 | A003 | 50 |
1)使用聚合函数 COUNT
计算订单表中的总订单数:
SELECT COUNT(*) AS order_num
FROM orders;
查询结果:
order_num |
---|
4 |
2)使用聚合函数 COUNT(DISTINCT 列名)
计算订单表中不同客户的数量:
SELECT COUNT(DISTINCT customer_id) AS customer_num
FROM orders;
查询结果:
customer_num |
---|
3 |
3)使用聚合函数 SUM
计算总订单金额:
SELECT SUM(amount) AS total_amount
FROM orders;
查询结果:
total_amount |
---|
500 |
单字段分组
在 SQL 中,分组聚合是一种对数据进行分类并对每个分类进行聚合计算的操作。它允许我们按照指定的列或字段对数据进行分组,然后对每个分组应用聚合函数,如 COUNT、SUM、AVG 等,以获得分组后的汇总结果。
举个例子:某个学校可以按照班级将学生分组,并对每个班级进行统计。查看每个班级有多少学生、每个班级的平均成绩。这样我们就能够对学校各班的学生情况有一个整体的了解,而不是单纯看个别学生的信息。
在 SQL 中,通常使用 GROUP BY
关键字对数据进行分组。
示例
假设有一个订单表 orders
,包含以下字段:order_id
(订单号)、product_id
(商品编号)、customer_id
(客户编号)、amount
(订单金额)。
数据如下:
order_id | product_id | customer_id | amount |
---|---|---|---|
1 | 1 | A001 | 100 |
2 | 1 | A002 | 200 |
3 | 1 | A001 | 150 |
4 | 1 | A003 | 50 |
5 | 2 | A001 | 50 |
要查询使用多字段分组查询表中 每个客户 购买的 每种商品 的总金额,相当于按照客户编号和商品编号分组:
-- 查询每个用户购买的每种商品的总金额,按照客户编号和商品编号分组
SELECT customer_id, product_id, SUM(amount) AS total_amount
FROM orders
GROUP BY customer_id, product_id;
查询结果:
customer_id | product_id | total_amount |
---|---|---|
A001 | 1 | 250 |
A001 | 2 | 50 |
A002 | 1 | 200 |
A003 | 1 | 50 |
having
在 SQL 中,HAVING 子句用于在分组聚合后对分组进行过滤。它允许我们对分组后的结果进行条件筛选,只保留满足特定条件的分组。
HAVING 子句与条件查询 WHERE 子句的区别在于,WHERE 子句用于在 分组之前 进行过滤,而 HAVING 子句用于在 分组之后 进行过滤。
多表查询
cross join
在 SQL 中,关联查询是一种用于联合多个数据表中的数据的查询方式。
其中,CROSS JOIN
是一种简单的关联查询,不需要任何条件来匹配行,它直接将左表的 每一行 与右表的 每一行 进行组合,返回的结果是两个表的笛卡尔积。
SELECT e.emp_name, e.salary, d.department, d.manager
FROM employees e
CROSS JOIN departments d;
上面的 SQL 还可以简化为:
SELECT e.emp_name, e.salary, d.department, d.manager
FROM employees e, departments d;
关联查询(inner-join)
在 SQL 中,INNER JOIN 是一种常见的关联查询方式,它根据两个表之间的关联条件,将满足条件的行组合在一起。
注意,INNER 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 |
---|---|---|
技术部 | 张三 | 上海 |
财务部 | 李四 | 北京 |
销售部 | 王五 | 广州 |
摸鱼部 | 赵二 | 吐鲁番 |
使用 INNER JOIN 进行关联查询,根据员工表和部门表之间的公共字段 部门名称(department)
进行匹配,将员工的姓名、工资以及所属部门和部门经理组合在一起:
SELECT e.emp_name, e.salary, e.department, d.manager
FROM employees e
JOIN departments d ON e.department = d.department;
查询结果如下:
emp_name | salary | department | manager |
---|---|---|---|
小明 | 5000 | 技术部 | 张三 |
鸡哥 | 6000 | 财务部 | 李四 |
李华 | 4500 | 销售部 | 王五 |
我们会发现,使用 INNER_JOIN 后,只有两个表之间存在对应关系的数据才会被放到查询结果中。
关联查询(outer-join)
在 SQL 中,OUTER JOIN 是一种关联查询方式,它根据指定的关联条件,将两个表中满足条件的行组合在一起,并 包含没有匹配的行 。
在 OUTER JOIN 中,包括 LEFT OUTER JOIN 和 RIGHT OUTER JOIN 两种类型,它们分别表示查询左表和右表的所有行(即使没有被匹配),再加上满足条件的交集部分。
SELECT e.emp_name, e.salary, e.department, d.manager
FROM employees e
LEFT JOIN departments d ON e.department = d.department;
注:左查询会将
employees
所有的行都罗列出来,然后满足条件的会将departments
中的信息带着
子查询
子查询是指在一个查询语句内部 嵌套 另一个完整的查询语句,内层查询被称为子查询。子查询可以用于获取更复杂的查询结果或者用于过滤数据。
当执行包含子查询的查询语句时,数据库引擎会首先执行子查询,然后将其结果作为条件或数据源来执行外层查询。
打个比方,子查询就像是在一个盒子中的盒子,外层查询是大盒子,内层查询是小盒子。执行查询时,我们首先打开小盒子获取结果,然后将小盒子的结果放到大盒子中继续处理。
示例
假设我们有以下两个数据表:orders
和 customers
,分别包含订单信息和客户信息。
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 |
customers 表:
customer_id | name | city |
---|---|---|
101 | Alice | New York |
102 | Bob | Los Angeles |
103 | Charlie | Chicago |
现在,我们希望查询出有订单总金额 > 200 的客户的姓名和城市信息,示例 SQL 如下:
-- 主查询
SELECT name, city
FROM customers
WHERE customer_id IN (-- 子查询SELECT DISTINCT customer_idFROM ordersWHERE total_amount > 200
);
在上述 SQL 中,先通过子查询从订单表中过滤查询出了符合条件的客户 id,然后再根据客户 id 到客户信息表中查询客户信息,这样可以少查询很多客户信息数据。
上述语句的查询结果:
name | city |
---|---|
Bob | Los Angeles |
Charlie | Chicago |
子查询(exists)
之前的教程讲到,子查询是一种强大的查询工具,它可以嵌套在主查询中,帮助我们进行更复杂的条件过滤和数据检索。
其中,子查询中的一种特殊类型是 “exists” 子查询,用于检查主查询的结果集是否存在满足条件的记录,它返回布尔值(True 或 False),而不返回实际的数据。
示例
假设我们有以下两个数据表:orders
和 customers
,分别包含订单信息和客户信息。
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 |
customers 表:
customer_id | name | city |
---|---|---|
101 | Alice | New York |
102 | Bob | Los Angeles |
103 | Charlie | Chicago |
104 | 赵二 | China |
现在,我们希望查询出 存在订单的 客户姓名和订单金额。
使用 exists 子查询的方式,SQL 代码如下:
-- 主查询
SELECT name, total_amount
FROM customers
WHERE EXISTS (-- 子查询SELECT 1FROM ordersWHERE orders.customer_id = customers.customer_id
);
上述语句中,先遍历客户信息表的每一行,获取到客户编号;然后执行子查询,从订单表中查找该客户编号是否存在,如果存在则返回结果。
查询结果如下:
name | total_amount |
---|---|
Alice | 200 |
Bob | 350 |
Charlie | 500 |
和 exists 相对的是 not exists,用于查找不满足存在条件的记录。
组合查询
在 SQL 中,组合查询是一种将多个 SELECT 查询结果合并在一起的查询操作。
包括两种常见的组合查询操作:UNION 和 UNION ALL。
-
UNION 操作:它用于将两个或多个查询的结果集合并, 并去除重复的行 。即如果两个查询的结果有相同的行,则只保留一行。
-
UNION ALL 操作:它也用于将两个或多个查询的结果集合并, 但不去除重复的行 。即如果两个查询的结果有相同的行,则全部保留。
示例
假设我们有以下两个数据表:table1
和 table2
,分别包含不同部门的员工信息。
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 |
现在,我们想要合并这两张表的数据,分别执行 UNION 操作和 UNION ALL 操作。
UNION 操作:
SELECT name, age, department
FROM table1
UNION
SELECT name, age, department
FROM table2;
UNION 操作的结果,去除了重复的行(名称为 Alice):
name | age | department |
---|---|---|
Alice | 25 | HR |
Bob | 28 | Finance |
Charlie | 22 | IT |
David | 27 | Finance |
Eve | 24 | HR |
Frank | 26 | IT |
UNION ALL 操作:
-- UNION ALL操作
SELECT name, age, department
FROM table1
UNION ALL
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 |
开窗函数
在 SQL 中,开窗函数是一种强大的查询工具,它允许我们在查询中进行对分组数据进行计算、 同时保留原始行的详细信息 。
开窗函数可以与聚合函数(如 SUM、AVG、COUNT 等)结合使用,但与普通聚合函数不同,开窗函数不会导致结果集的行数减少。
打个比方,可以将开窗函数想象成一种 “透视镜”,它能够将我们聚焦在某个特定的分组,同时还能看到整体的全景。
sum over
本节我们先讲第一个开窗函数: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 |
现在,我们希望计算每个客户的订单总金额,并显示每个订单的详细信息。
示例 SQL 如下:
SELECT order_id, customer_id, order_date, total_amount,SUM(total_amount) OVER (PARTITION BY customer_id) AS customer_total_amount
FROMorders;
查询结果:
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 进行分组。从前两行可以看到,开窗函数保留了原始订单的详细信息,同时计算了每个客户的订单总金额。
示例
假设我们有订单表 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 |
现在,我们希望计算每个客户的订单总金额,并显示每个订单的详细信息。
示例 SQL 如下:
SELECT order_id, customer_id, order_date, total_amount,SUM(total_amount) OVER (PARTITION BY customer_id) AS customer_total_amount
FROMorders;
查询结果:
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 进行分组。从前两行可以看到,开窗函数保留了原始订单的详细信息,同时计算了每个客户的订单总金额。
sum over (partition … by … order by … asc)
注:这个是一个一个累加上去,并且按照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
FROMorders;
结果将是:
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,同组内的累加列名称
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
FROMorders;
查询结果:
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 从大到小进行排序。
可以看到,开窗函数保留了原始订单的详细信息,同时计算了每个客户的订单金额排名。
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 编号,示例 SQL 语句如下:
SELECT order_id, customer_id, order_date, total_amount,ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY total_amount DESC) AS row_number
FROMorders;
结果将是:
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 进行排序。
lag / lead
开窗函数 Lag 和 Lead 的作用是获取在当前行之前或之后的行的值,这两个函数通常在需要比较相邻行数据或进行时间序列分析时非常有用。
1)Lag 函数
Lag 函数用于获取 当前行之前 的某一列的值。它可以帮助我们查看上一行的数据。
Lag 函数的语法如下:
LAG(column_name, offset, default_value) OVER (PARTITION BY partition_column ORDER BY sort_column)
参数解释:
column_name
:要获取值的列名。offset
:表示要向上偏移的行数。例如,offset为1表示获取上一行的值,offset为2表示获取上两行的值,以此类推。default_value
:可选参数,用于指定当没有前一行时的默认值。PARTITION BY
和ORDER BY
子句可选,用于分组和排序数据。
2)Lead 函数
Lead 函数用于获取 当前行之后 的某一列的值。它可以帮助我们查看下一行的数据。
Lead 函数的语法如下:
LEAD(column_name, offset, default_value) OVER (PARTITION BY partition_column ORDER BY sort_column)
参数解释:
column_name
:要获取值的列名。offset
:表示要向下偏移的行数。例如,offset为1表示获取下一行的值,offset为2表示获取下两行的值,以此类推。default_value
:可选参数,用于指定当没有后一行时的默认值。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 |
现在我们想要查询每个学生的考试日期和上一次考试的成绩,以及下一次考试的成绩,示例 SQL 如下:
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
FROMscores;
结果将是:
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 |
在上面的示例中,我们使用 Lag 函数获取每个学生的上一次考试成绩(previous_score),使用 Lead 函数获取每个学生的下一次考试成绩(next_score)。如果没有上一次或下一次考试,对应的列将显示为 NULL。