简单来说就是 将 一个查询SQL 的结果集按指定的规则进行分区,每个分区可以看作是一个窗口,分区内的每一行,根据其所属分区内的行数据进行函数计算,获取计算结果,作为该行的窗口函数结果值
-group by使用聚合函数,普通场景下的聚合函数是将多条记录聚合为一条(多到一)-窗口函数是每条记录都会执行,有几条记录执行完还是几条(多到多)
语法:
函数名(字段名) over(partition by <要分列的组> order by <要排序的列> rows between <数据范围>)
rows between 2 preceding and current row #本行和前面两行
rows between unbounded preceding and current row #本行和之前所有的行 #unbounded意为无限的
rows between current row and unbounded following # 本行和之后所有的行rows between 3 preceding and 1 following # 从前面三行和下面一行,总共五行
-- 当order by后面没有rows between时,窗口规范默认是取本行和之前所有的行
-- 当order by和rows between都没有时,窗口规范默认是分组下所有行
一、累计和:SUM(字段) over()
二、最大最小:MAX(字段)over()、MIN(字段)over()
三、移动平均:AVG(字段)over()
四、排名排序:Rank()over()
五、前后取值【相隔差】:LAG(字段,n)over()、LEAD(字段,n)over()
六、首位末位:first_value(字段)over()、last_value()over()
七、第N个:NTH_VALUE(expr,n)over()
八、分桶分箱(分等级)NTILE(n)over()
-- 窗口语法:函数名(字段名)over(子句)
【场景1】 累计和:sum(字段)over()
#示例:求每天的总金额
select order_date,payble,sum(payble) from order_info group by order_date order by order_date;
select order_date,payble, -- 数据排序
sum(payble) over (PARTITION BY order_date ORDER BY order_date) total1,
sum(payble) over (PARTITION BY order_date) total2
from order_info;
【场景2】最大最小:MAX(字段)over()、MIN(字段)over()
#示例:求每天的最早订单和最晚订单时间
select distinct order_date,
min(start_time) over(partition by order_date) mintime,
max(start_time) over(partition by order_date) maxtime
from order_info;
select order_date,min(start_time),max(start_time)
from order_info group by order_date order by order_date;
【场景3】移动平均:AVG(字段)OVER() ***重点理解这题****
# 移动平均,查看每天包括前1天的平均金额
with a as(
select order_date,sum(payble) spay from order_info group by order_date)
select order_date,spay,
avg(spay) over(order by order_date rows between 1 preceding and current row) rowvpay from a; #本行和前面1行,即题目的每天包括前一天
【场景4】排名:RANK() OVER()
# 查询order_detail 数据表中每个订单下价格降序排列的各个明细信息
select detail_id,order_id,amounts,
# 顺序排序
row_number() over(partition by order_id order by amounts desc) row_num,
# 并列排序,会跳过重复的序号(如:12 12 14,其中第二个12是跳过的重复的,第三个为14)
rank() over(partition by order_id order by amounts desc) ranks,
# 并列排序,不会跳过重复的序号(如:14 14 15,不跳过重复值,两个14后第三个值还是15)
dense_rank() over(partition by order_id order by amounts desc) dranks,
#等级值百分比
PERCENT_RANK() OVER(PARTITION BY order_id ORDER BY amounts DESC) pranks,
# 累计分布值
CUME_DIST() OVER(PARTITION BY order_id ORDER BY amounts DESC) cranks
from order_detail;
【场景5】前后取值:LAG(字段,n) OVER()、LEAD(字段,n) OVER()
示例:计算每个订单与后一个订单的金额差【相隔用lead()】
with a as(
select *,lead(payble,1) over(order by payble) pay2 from order_info)
select info_id,payble,pay2 ,pay2-payble 差值 from a;
【场景6】首位末位:FIRST_VALUE(字段) OVER()、LAST_VALUE(字段) OVER()
# 示例:info表中,每天第一个和最后一个订单记录的订单时间
select DISTINCT order_date, FIRST_VALUE(start_time) over (PARTITION BY order_date ) total1,
LAST_VALUE(start_time) over (PARTITION BY order_date ) total2
from order_info ;
*****多个查询结果表利用的嵌套,两个with x as()即可实现*********
-- 问题:比较每天与上周同一天(周一对周一)的订单总金额【隔几天用lead()】
select * from order_info; dishes_count*payble总金额
with b as(
with a as(
select start_time,sum(dishes_count*payble) 订单总金额 from order_info group by date(start_time) order by date(start_time))
select date(start_time),订单总金额,lead(订单总金额,7) over(order by date(start_time)) 每周同一天的订单总金额 from a)
select *,订单总金额-每周同一天的订单总金额 每周同一天的订单总金额差值 from b;
【场景7】第N个:NTH_VALUE(expr, n) OVER()
示例:每个订单中价格第一和第二的菜的id号【排序,排第几第几用nth_value()】
select * from order_detail;
select DISTINCT order_id,amounts,
# desc降序后,nth_value(dishes_id,1)为价格排名第一对应的菜品编号
NTH_VALUE(dishes_id,1) over (PARTITION BY order_id ORDER BY amounts desc) id1,
# desc降序后,nth_value(dishes_id,2)为价格排名第二对应的菜品编号
NTH_VALUE(dishes_id,2) over (PARTITION BY order_id ORDER BY amounts desc) id2
from order_detail;
【场景8】分桶分箱:NTILE(n) OVER()
示例:把菜品单价分成5个等级
select DISTINCT amounts, NTILE(5) over (ORDER BY amounts) nprice
from order_detail;