SQL视频这么火,你会这么分析吗?(分组汇总、相邻判断、偏移函数)

本文通过短视频平台的实际案例,演示了如何运用SQL的分组汇总及窗口函数解决数据分析中的常见问题,包括统计每天访客数和平均操作次数,以及特定操作序列的用户数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【题目】

"用户操作记录表"里记录着每天某短视频平台的用户点击访问情况,以便帮助公司内部分析师了解用户对于当前页面的点击偏好。
表包字段有:用户名、操作记录、操作时间。

其中表内各字段含义如下

用户名:表示用户在该短视频平台注册的唯一用户名。

操作记录:表示用户在该短视频平台点击的按钮名称。A表示用户点击“短视频”播放入口,B表示用户点击“长视频”播放入口。

操作时间:表示用户点击时候的时间,精确到秒。

现在运营人员找到作为数据分析师的你,想让你帮忙看看用SQL取两个数据,具体如下:

1.分析每天的访客数和他们的平均操作次数

2.统计每天符合以下条件的用户数:A操作之后是B操作,AB操作必须相邻。

举个例子,比如小明在2020年1月2日当天先点了短视频入口(操作ID为A),其后又点了长视频入口(操作ID为B),那么小明就属于当天我们的目标用户。(如下图黄色字段所示)

1.分析每天的访客数和他们的平均操作次数

假如短视频平台2020年1月2号正式上线,第一天,只有小明和小红两个人浏览短视频平台。

其中小明对短视频和长视频都感兴趣,上午九点点击了A按钮进入短视频界面观看。然后下午3点钟,小明点了B按钮,进入长视频频道观看。晚上时候,小明觉着还想再看看短视频,就在晚上7点40时候,又点击了A按钮去观看短视频。

而小红是重度短视频爱好者,当天下午2点小红第一次点击A按钮进入短视频界面,觉着内容不错,于是晚上6点时候,又点击了A按钮,又开心的看短视频。

那么,如何统计当天访客数以及平均操作次数呢?

短视频平台上线第一天,也就是2020年1月2日,当天的访客数和平均操作次数我们可以很轻而易举的看出来:当天访客数是2(小明和小红两人),当天的平均操作次数是2.5次(当天一共有5次点击行为,2个人操作,所以5除以2得2.5)

然而,随着短视频平台人数的增多,如果让分析师天天进行手动数数,那工作量可想而知,有什么方式可以帮我们快速统计每天的访客数和平均操作次数呢?

题目中想要知道每天的访客数和平均操作次数,遇到这类“每个”的问题,要想到《猴子 从零学会SQL》里讲过的用“分组汇总”。

按日期分组(group by日期),汇总(人数用count用户名,操作数用count操作时间)。这里因为表中代表日期的字段“操作时间”是精确到分秒的,所以需要利用date函数将操作时间转为日期形式。具体形式如下:

这里你可以会存在一个疑问,既然group by代表分组意思,我直接在结尾时候增添group by分组命令即可,但为什么在开头的select 后面,也需要加上分组标准date(操作时间)呢?

这就涉及到聚合函数另一个特点,“首尾呼应”。你可以简单理解为,select后面为最后呈现在餐桌上的美味佳肴,而group by后面的内容为厨房幕后烹饪的食材加工过程。

理解清楚后,代入具体代码字段如下:


select date(操作时间) as 操作日期,
       count(distinct 用户名) as 人数,
       avg(操作时间) as 操作数
from 用户操作记录表
group by date(操作时间);

这里有两个注意点,其一是需要去重,count(distinct 用户名)其中的distinct就是去重的意思。

比如小明在2020-02-01早上点了一次,下午点了一次,晚上点了一次,那么小明其实在表里面当天是有三条记录的,但是人头数的话,小明当天只贡献了一个人头数,所以这里需要去重。

其二是日期需要改为date形式,date函数可以帮我们将长时间段变为简介的年-月-日的日期形式。

2.统计每天符合以下条件的用户数:A操作之后是B操作,AB操作必须相邻

其实这个是在日常工作中业务经常要用到的SQL取数场景。例如,某电商公司主管在做针对功能优化的决策,主管非常想知道,咱们的用户在点击“下单”按钮后,都流向到哪里去了?

这时候数据分析师小甲淡定的汇报到:主管,咱们用户呀,在点击“下单”按钮后,有80%的用户立马点击了“领优惠券”按钮,有15%的用户立马点击了“评价”按钮,有5%的用户立马点击了“随便看看”按钮。

主管一听,便立马就知道了用户的点击行为偏好。

其实这里,数据分析师小甲用了SQL中的lead()窗口函数,实现了这种“相邻”操作的数据统计。

 

如上图可知,用户(花花)的行为路径是,先下单,其后他领取了优惠券,领完优惠券之后再去评价。而小白则是下单后直接就去评价了。

数据分析师小甲先以用户进行分组,找出用户当前操作以及最近一次操作的行为,而后进行统计记人头数,从而给了主管一个非常满意的答案。

lead()函数的模板如上,基本上只要改变ABC三个方格里面的值,就可以实现任何相邻元素之间的取数。具体表达含义如下:

lead()表示找出XXX的下一次相邻行为。

partition表示分组

order by表示排序;

比如说,想找出每天用户相邻两次的点击。

按照什么分组呢?按照用户分组,所以partition by后面填上用户id。

那如何区别每个用户各个行为的先后顺序呢?按照每个用户点击的时间来区分,所以order by后面填入操作时间。

那最后,我们究竟想看的行为是什么呢?操作记录(比如上述提到的优惠券行为、评价行为等)。

思路整理完后,SQL如下:


lead(操作ID,1) over(partition by 用户名 
                    order by 操作时间);

回过头来继续看当前的这个案例。

假如短视频平台2020年1月2号正式上线,第一天,只有小明和小红两个人浏览短视频平台。

其中小明对短视频和长视频都感兴趣,上午九点点了A按钮进入短视频界面观看。其后下午3点钟,小明点了B按钮,进入长视频频道观看。

晚上时候,小明觉着还想再看看短视频,就在晚上7点40时候,又点击了A按钮去观看短视频。

小红则是重度短视频爱好者,当天下午2点小红第一次点击A按钮进入短视频界面,觉着内容不错,于是晚上6点时候,又点击了A按钮,又开心的看短视频。

这里找出A操作后,立马是B操作后的用户数,具体思路如下。

首先按照用户名进行分组,其次按照每个用户名下用户的点击时间进行排序,最后以操作记录作为我们想要定位的行为。

如下,黄色部分表示,当小明点击A按钮观看短视频后,其后下一次最近的行为是点击B按钮观看了长视频。白色部分表示,当小明点击B按钮观看长视频后,其后下一次最近的行为是又在晚上时候点击A按钮观看了短视频。

红色部分则代表了小红的行为路径,小红最初是点击A按钮观看短视频,其后又再次点击了A按钮观看了短视频。

从而可以写出第一条SQL语句:

 最终SQL如下:


select 操作时间,count(distinct 用户名) as 用户数
from
(select date(操作时间) as 操作时间,用户名,
操作记录,lead(操作记录,1) over(partition by 用户名order by 操作时间) as 最近的下一次操作记录
from tracking_log) t
where 操作记录=‘A’ and 最近的下一次操作记录='B'
group by 操作时间

 

 

【本题考点】

1.考查对分组汇总的应用,以及灵活使用来解决业务问题

2.当遇到相邻问题时,要想到用窗口函数lead来解决

3.考察遇到复杂问题,如何用逻辑树分析方法来拆解解决成简单问题

 

 

<think>好的,我现在需要帮助用户了解Oracle数据库偏移函数的使用方法和示例。用户之前已经询问过`PARTITION BY`和`GROUP BY`的区别,现在转向具体的偏移函数,也就是LAG和LEAD。根据用户提供的引用内容,这些函数用于访问同一字段的前后行数据,代替自连接,提高效率。 首先,我需要确认用户的需求。他们可能是在处理需要比较当前行与前后行数据的场景,比如计算时间序列中的变化,或者查找相邻记录之间的差异。用户可能已经了解窗口函数的基本概念,现在需要更具体的应用指导。 接下来,我需要整理LAG和LEAD的基本语法和参数。根据引用,这些函数有三个参数:字段名、偏移行数和默认值。例如,LAG(column, n, default) OVER (PARTITION BY ... ORDER BY ...)。需要解释每个参数的作用,特别是默认值在数据不足时的应用。 然后,应用场景是关键。用户可能想知道什么时候使用这些函数。比如计算增长率,查找相邻订单的时间差,或者检测数据变化点。需要举出实际的例子,如销售数据的逐月比较,或用户登录时间的间隔分析。 示例部分需要详细,最好包括SQL代码和结果。例如,使用LAG获取前一月的销售额,并计算环比增长率。同时,要注意PARTITION BY和ORDER BY子句的使用,确保数据正确分组和排序。 另外,用户可能对性能优化感兴趣。引用中提到LAG和LEAD比自连接更高效,所以需要强调这一点,并建议合理使用分区和排序,避免不必要的计算。 还需要注意常见问题,比如如何处理首尾行的默认值,以及在使用ORDER BY时对窗口范围的影响。比如,默认情况下,LAG和LEAD的窗口范围是从分区开始到当前行,但用户可能需要调整。 最后,检查是否有遗漏点。比如,是否提到了LEAD函数的反向功能,或者如何结合其他窗口函数使用。同时,确保回答结构清晰,步骤明确,符合用户要求的真实可靠。</think>### Oracle 偏移函数(LAG/LEAD)用法详解 --- #### **核心功能与语法** Oracle 的 **`LAG`** 和 **`LEAD`** 是分析函数,用于**访问当前行的前/后N行数据**,避免复杂的自连接操作,提升查询效率[^1][^2][^4]。 **语法结构**: ```sql LAG(column, offset, default) OVER ( [PARTITION BY group_expression] ORDER BY sort_expression [ASC|DESC] ) LEAD(column, offset, default) OVER ( [PARTITION BY group_expression] ORDER BY sort_expression [ASC|DESC] ) ``` **参数说明**: - **`column`**:目标字段(如销售额、时间戳) - **`offset`**:偏移行数(默认1) - **`default`**:无数据时的默认值(如NULL或0) - **`PARTITION BY`**:分组依据(类似分组窗口) - **`ORDER BY`**:排序规则(决定数据顺序) --- #### **典型应用场景** ##### 1. **相邻行差值计算** **示例**:计算每日销售额环比增长率 ```sql SELECT sale_date, amount, LAG(amount, 1, 0) OVER (ORDER BY sale_date) AS prev_amount, ROUND((amount - LAG(amount, 1, 0) OVER (ORDER BY sale_date)) / LAG(amount, 1, 0) OVER (ORDER BY sale_date) * 100, 2) AS growth_rate FROM sales; ``` **输出**: | SALE_DATE | AMOUNT | PREV_AMOUNT | GROWTH_RATE | |-----------|--------|-------------|-------------| | 2023-01-01| 1000 | 0 | NULL | | 2023-01-02| 1500 | 1000 | 50.00 | | 2023-01-03| 1200 | 1500 | -20.00 | --- ##### 2. **时间间隔分析** **示例**:统计用户连续两次登录的时间差 ```sql SELECT user_id, login_time, LEAD(login_time, 1) OVER (PARTITION BY user_id ORDER BY login_time) AS next_login, LEAD(login_time, 1) OVER (PARTITION BY user_id ORDER BY login_time) - login_time AS interval FROM user_logins; ``` **输出**: | USER_ID | LOGIN_TIME | NEXT_LOGIN | INTERVAL | |---------|---------------------|--------------------|-------------------| | 101 | 2023-08-01 09:00:00 | 2023-08-01 14:30:00| +0 05:30:00.000000| | 101 | 2023-08-01 14:30:00 | 2023-08-02 08:45:00| +0 18:15:00.000000| --- ##### 3. **数据状态变化检测** **示例**:标记订单状态变化节点 ```sql SELECT order_id, status, update_time, LAG(status, 1, 'N/A') OVER (PARTITION BY order_id ORDER BY update_time) AS prev_status, CASE WHEN status != LAG(status, 1, 'N/A') OVER (PARTITION BY order_id ORDER BY update_time) THEN 'Changed' ELSE 'Unchanged' END AS status_change FROM order_history; ``` **输出**: | ORDER_ID | STATUS | UPDATE_TIME | PREV_STATUS | STATUS_CHANGE | |----------|-----------|---------------------|-------------|---------------| | 2001 | CREATED | 2023-08-01 10:00:00 | N/A | Changed | | 2001 | PAID | 2023-08-01 11:30:00 | CREATED | Changed | | 2001 | SHIPPED | 2023-08-02 09:00:00 | PAID | Changed | --- #### **关键注意事项** 1. **排序规则影响结果** 必须明确指定`ORDER BY`,否则偏移方向可能混乱: ```sql -- 错误示例(缺少ORDER BY) LAG(amount) OVER (PARTITION BY dept) -- 结果不可预测 ``` 2. **窗口范围控制** 默认窗口为当前分区的全部数据,可自定义范围: ```sql -- 仅比较前3行数据 LAG(amount, 3) OVER (ORDER BY sale_date ROWS BETWEEN 3 PRECEDING AND CURRENT ROW) ``` 3. **性能优化** - 避免在`PARTITION BY`中使用高基数字段(如用户ID) - 减少不必要的偏移量(`offset`值过大影响内存) --- #### **与其他函数的结合使用** 1. **与`ROW_NUMBER`配合去重** ```sql SELECT * FROM ( SELECT id, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY login_time DESC) AS rn, LAG(login_time) OVER (PARTITION BY user_id ORDER BY login_time) AS prev_login FROM logins ) WHERE rn = 1; -- 取最新登录记录 ``` 2. **与聚合函数叠加计算** ```sql SELECT dept, AVG(salary) AS avg_sal, AVG(salary) - LAG(AVG(salary)) OVER (ORDER BY dept) AS diff_from_prev_dept FROM employees GROUP BY dept; ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值