MySQL高级应用窗口函数之偏移分析函数

·  阅读 1072

前言

本篇将通过示例讲解:偏移分析函数+over()

一、偏移分析函数概念

  • lag(col,n,default):用于统计分组内往上第n行值。

    • 第一个参数为列名
    • 第二个参数为往上第n行(可选,不填默认为1)
    • 第三个参数为默认值(当往上第n行为NULL时候,取默认值,如不指定,则为NULL)
  • lead(col,n,default):与lag相反,统计分组内往下第n行值。

    • 第一个参数为列名
    • 第二个参数为往下第n行(可选,不填默认为1)
    • 第三个参数为默认值(当往下第n行为NULL时候,取默认值,如不指定,则为NULL)
  • first_value(col):用于取分组内排序后,截止到当前行,第一个col的值。

  • last_value(col):用于取分组内排序后,截止到当前行,最后一个col的值。

二、示例讲解

2.1 案例

查询出用户【yantian】和【lisi】的时间偏移(前N行)

分析:通过lag()窗口函数进行实现

SELECT
	user_name,
	pay_time,
	lag( pay_time, 1, pay_time ) over ( PARTITION BY user_name ORDER BY pay_time ) lag1,
	lag( pay_time ) over ( PARTITION BY user_name ORDER BY pay_time ) lag2,
	lag( pay_time, 2, pay_time ) over ( PARTITION BY user_name ORDER BY pay_time ) lag3,
	lag( pay_time, 2 ) over ( PARTITION BY user_name ORDER BY pay_time ) lag4 
FROM
	user_order 
WHERE
	user_name IN ( 'lisi', 'yantian' )
复制代码

运行结果

05.MySQL高级应用窗口函数(四)01.jpg

2.2 案例

查询出用户【yantian】和【lisi】的时间偏移(后N行)

分析:通过lead()窗口函数进行实现

SELECT
	user_name,
	pay_time,
	lead( pay_time, 1, pay_time ) over ( PARTITION BY user_name ORDER BY pay_time ) lead1,
	lead( pay_time ) over ( PARTITION BY user_name ORDER BY pay_time ) lead2,
	lead( pay_time, 2, pay_time ) over ( PARTITION BY user_name ORDER BY pay_time ) lead3,
	lead( pay_time, 2 ) over ( PARTITION BY user_name ORDER BY pay_time ) lead4 
FROM
	user_order 
WHERE
	user_name IN ( 'lisi', 'yantian' );
复制代码

运行结果

05.MySQL高级应用窗口函数(四)02.jpg

2.3 案例

查询出支付时间间隔超过10天的用户数

分析:

  • 同一用户,相邻的订单进行下单时间比较,如果相邻订单下单时间间隔超过10天,那么这个用户就是需要统计的
  • 在这个过程中,需要进行相邻订单支付时间相减

实现步骤

(1)通过lead窗口函数根据支付时间进行分组,将下一行支付时间移到上一行当中
(2)通过上一步将支付时间做差,然后对用户去重,再进行count操作
复制代码

实现

步骤一:通过lead窗口函数根据支付时间进行分组,将下一行支付时间移到上一行当中

SELECT
	user_name,
	pay_time,
	lead( pay_time, 1 ) over ( PARTITION BY user_name ORDER BY pay_time ) lead_time 
FROM
	user_order;
复制代码

步骤二:通过上一步将支付时间做差,然后对用户去重,再进行count操作

SELECT
	count( DISTINCT user_name ) 
FROM
	( SELECT user_name, pay_time, lead( pay_time, 1 ) over ( PARTITION BY user_name ORDER BY pay_time ) lead_time FROM user_order ) a 
WHERE
	datediff( a.lead_time, a.pay_time )> 10;
复制代码

05.MySQL高级应用窗口函数(四)03.jpg

2.4 案例

查询出每年支付时间间隔最长的用户

实现步骤

(1)根据用户和支付年份进行分组,通过lag()窗口函数将上一行的支付时间合并到下一行
(2)计算订单时间间隔,在年度内按照各自的订单时间间隔进行排名
(3)将上方查询结果作为表进行子查询,取得排名结果为1的值
复制代码

实现

步骤一:根据用户和支付年份进行分组,通过lag()窗口函数将上一行的支付时间合并到下一行

SELECT YEAR
	( pay_time ) year_time,
	user_name,
	pay_time,
	lag( pay_time ) over ( PARTITION BY user_name, YEAR ( pay_time ) ORDER BY pay_time ASC ) lag_time 
FROM
	user_order;
复制代码

步骤二:计算订单时间间隔,在年度内按照各自的订单时间间隔进行排名

SELECT
	a.year_time,
	a.user_name,
	datediff( a.pay_time, a.lag_time ) interval_days,
	rank() over ( PARTITION BY a.year_time ORDER BY datediff( a.pay_time, a.lag_time ) DESC ) rank1 
FROM
	(
	SELECT YEAR
		( pay_time ) year_time,
		user_name,
		pay_time,
		lag( pay_time ) over ( PARTITION BY user_name, YEAR ( pay_time ) ORDER BY pay_time ASC ) lag_time 
	FROM
		user_order 
	) a;
复制代码

步骤三:将上方查询结果作为表进行子查询,取得排名结果为1的值

SELECT
	b.year_time,
	b.user_name,
	b.interval_days 
FROM
	(
	SELECT
		a.year_time,
		a.user_name,
		datediff( a.pay_time, a.lag_time ) interval_days,
		rank() over ( PARTITION BY a.year_time ORDER BY datediff( a.pay_time, a.lag_time ) DESC ) rank1 
	FROM
		(
		SELECT YEAR
			( pay_time ) year_time,
			user_name,
			pay_time,
			lag( pay_time ) over ( PARTITION BY user_name, YEAR ( pay_time ) ORDER BY pay_time ASC ) lag_time 
		FROM
			user_order 
		) a 
	) b
	where b.rank1 = 1;
复制代码

运行结果

05.MySQL高级应用窗口函数(四)04.jpg

分类:
后端
标签: