拿捏SQL:以“统计连续登录天数超过3天的用户“为例拿捏同类型SQL需求

news2024/10/2 3:22:50

文章目录

    • @[TOC](文章目录)
  • 一、介绍
    • 案例:以"统计连续登录天数超过3天的用户"为需求。
      • 数据准备
      • 方案1:常规思路
        • 针对对数据user_id分组,根据用户的活动日期排序
        • 用登录日期与rn求date_sub,得到的差值日期如果是相等的,则说明这两天肯定是连续的
        • 根据user_id和日期差sub_date分组,登录次数即为分组后的count(1)
      • 方案2:使用lag和lead函数
        • 使用LEAD和LAG函数求出前后1天日期
        • 针对每个用户,进行前一天和后一天的日期与当期日期相差值=1则属于连续登录。
        • 针对用户分组,datediff函数求出最大活动时间和最小活动时间的天数,求出>=3天的用户
        • 对比方案1和方案2


  • 作为大数据开发人员,绝不能丢下SQL能力。

一、介绍

在我们工作ETL或者在进行大数据面试的时候,总是常常会被手撕SQL,而常见的SQL有连续登录问题。一般的问法是“统计连续登录N天XX的XX”。
小编今天在这里给大家介绍两种方案轻松让你拿捏这类SQL问题。

mysql8.x和hive很多函数已经基本差不多都能满足了,为了执行效率和方便,这里以mysql为例,其他SQL类似,如果有不清楚的可以评论区留言。

案例:以"统计连续登录天数超过3天的用户"为需求。

数据准备

在mysql中执行以下代码,生成相应的数据表

-- ----------------------------
-- Table structure for user_activity
-- ----------------------------
DROP TABLE IF EXISTS `user_activity`;
CREATE TABLE `user_activity`  (
  `user_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
  `activity_date` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user_activity
-- ----------------------------
INSERT INTO `user_activity` VALUES ('user1', '2023-03-01');
INSERT INTO `user_activity` VALUES ('user2', '2023-03-02');
INSERT INTO `user_activity` VALUES ('user3', '2023-03-03');
INSERT INTO `user_activity` VALUES ('user4', '2023-03-04');
INSERT INTO `user_activity` VALUES ('user1', '2023-03-08');
INSERT INTO `user_activity` VALUES ('user2', '2023-03-08');
INSERT INTO `user_activity` VALUES ('user5', '2023-03-08');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-08');
INSERT INTO `user_activity` VALUES ('user3', '2023-03-09');
INSERT INTO `user_activity` VALUES ('user5', '2023-03-09');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-09');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-09');
INSERT INTO `user_activity` VALUES ('user3', '2023-03-10');
INSERT INTO `user_activity` VALUES ('user5', '2023-03-10');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-10');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-10');
INSERT INTO `user_activity` VALUES ('user5', '2023-03-11');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-11');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-11');
INSERT INTO `user_activity` VALUES ('user6', '2023-03-12');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-12');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-13');
INSERT INTO `user_activity` VALUES ('user8', '2023-03-13');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-14');
INSERT INTO `user_activity` VALUES ('user8', '2023-03-14');
INSERT INTO `user_activity` VALUES ('user7', '2023-03-15');
INSERT INTO `user_activity` VALUES ('user8', '2023-03-15');
INSERT INTO `user_activity` VALUES ('user8', '2023-03-16');
SELECT * FROM `user_activity`

结果如下:

user1	2023-03-01
user2	2023-03-02
user3	2023-03-03
user4	2023-03-04
user1	2023-03-08
user2	2023-03-08
user5	2023-03-08
user6	2023-03-08
user3	2023-03-09
user5	2023-03-09
user6	2023-03-09
user7	2023-03-09
user3	2023-03-10
user5	2023-03-10
user6	2023-03-10
user7	2023-03-10
user5	2023-03-11
user6	2023-03-11
user7	2023-03-11
user6	2023-03-12
user7	2023-03-12
user7	2023-03-13
user8	2023-03-13
user7	2023-03-14
user8	2023-03-14
user7	2023-03-15
user8	2023-03-15
user8	2023-03-16

在这里插入图片描述

方案1:常规思路

  • 1、先对数据user_id分组,根据用户的活动日期排序
  • 2、用登录日期与rn求date_sub,得到的差值日期如果是相等的,则说明这两天肯定是连续的
    • 举例说,2023年1月1号、1月2号、1月3号;排名分别是1,2,3;现在用日期 - 排名 是不是都等于2022年12月31号
  • 3、根据user_id和日期差sub_date分组,登录次数即为分组后的count(1)

针对对数据user_id分组,根据用户的活动日期排序

select
			user_id,
			activity_date,
			ROW_NUMBER() over(partition by user_id order by activity_date) as rn
from user_activity

在这里插入图片描述

用登录日期与rn求date_sub,得到的差值日期如果是相等的,则说明这两天肯定是连续的

SELECT
		user_id,
		activity_date,
		DATE_SUB(activity_date,INTERVAL rn DAY) as sub_date
	from(
		select
			user_id,
			activity_date,
			ROW_NUMBER() over(partition by user_id order by activity_date) as rn
		from user_activity
	)t1

在这里插入图片描述

根据user_id和日期差sub_date分组,登录次数即为分组后的count(1)

SELECT
	user_id,
	min(activity_date) as min_date,
	max(activity_date)  as max_date,
	count(1) as  login_times
from(
	SELECT
		user_id,
		activity_date,
		DATE_SUB(activity_date,INTERVAL rn DAY) as sub_date
	from(
		select
			user_id,
			activity_date,
			ROW_NUMBER() over(partition by user_id order by activity_date) as rn
		from user_activity
	)t1
)t2
group by user_id,sub_date
having login_times>=3;

在这里插入图片描述

  • 从结果可以看出用户5,6,7,8存在连续登录3天及其以上的用户

方案2:使用lag和lead函数

  • 1、针对每个user_id,先使用lag和lead函数将当前日期的前一天和后后一天日期求出来
  • 2、针对每个用户,进行前一天和后一天的日期与当期日期相差值=1则属于连续登录。
    • 举例说,2023年1月1号、1月2号、1月3号;现在用日期2号 - 前后与它相差值2-1=1;3-2=1.是不是值都否为1呢。
  • 3、针对用户分组,datediff函数求出最大活动时间和最小活动时间的天数,求出>=3天的用户

使用LEAD和LAG函数求出前后1天日期

select
		user_id,
		LAG(activity_date,1,activity_date) over(partition by user_id order by activity_date) as lag_login_date,
		activity_date as current_login_date,
		LEAD(activity_date,1,activity_date) over(partition by user_id order by activity_date) as lead_login_date
	from user_activity

在这里插入图片描述

针对每个用户,进行前一天和后一天的日期与当期日期相差值=1则属于连续登录。

SELECT
	user_id,
	lag_login_date,
	current_login_date,
	lead_login_date
from(
	select
		user_id,
		LAG(activity_date,1,activity_date) over(partition by user_id order by activity_date) as lag_login_date,
		activity_date as current_login_date,
		LEAD(activity_date,1,activity_date) over(partition by user_id order by activity_date) as lead_login_date
	from user_activity
)t1
where datediff(current_login_date,lag_login_date)=1 
and datediff(lead_login_date,current_login_date)=1;

针对用户分组,datediff函数求出最大活动时间和最小活动时间的天数,求出>=3天的用户

SELECT
	user_id,
	min(activity_date) as min_date,
	max(activity_date)  as max_date,
	count(1) as  login_times
from(
	SELECT
		user_id,
		activity_date,
		DATE_SUB(activity_date,INTERVAL rn DAY) as sub_date
	from(
		select
			user_id,
			activity_date,
			ROW_NUMBER() over(partition by user_id order by activity_date) as rn
		from user_activity
	)t1
)t2
group by user_id,sub_date
having login_times>=3;

在这里插入图片描述

对比方案1和方案2

方案1,想法很简单,更容易实现,简单了解开窗排序函数和基础SQL能力即可完成。难度中
,
方案2,想法简单,实现难度更大一些,需要对开窗函数有一定的掌握和熟练。难度高


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/484809.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python非线性回归预测模型实验完整版

非线性回归预测模型 实验目的 通过非线性回归预测模型,掌握预测模型的建立和应用方法,了解非线性回归模型的基本原理 实验内容 非线性回归预测模型 实验步骤和过程 (1)第一步:学习非线性回归预测模型相关知识。 非线性回归预测模型是指…

Spring框架中的单例Beans是线程安全的么?

在Spring框架中,单例Beans默认是线程安全的。 当你在Spring框架中声明一个单例Bean并配置为默认的单例作用域时,Spring会确保对该Bean的并发访问是线程安全的。以下是一个简单的代码演示: 假设我们有一个名为 SingletonBean 的单例 Bean 类…

Mysql目录结构

一、目录结构 <1> 主要目录结构 find / -name mysql<2> 数据库文件目录 目录&#xff1a;/var/lib/mysql/ 配置方式&#xff1a;show variables like ‘datadir’; <3> 相关命令目录 目录&#xff1a;/usr/bin&#xff08;mysqla…

VMware安装CentOS7遇到的问题记录

文章目录 1、执行ifconfig后&#xff0c;ip地址不显示解决方法&#xff1a; 2、CentOS ip地址老是变动&#xff0c;配置固定ip解决方法 1、执行ifconfig后&#xff0c;ip地址不显示 问题背景&#xff1a;VMware安装centos7后&#xff0c;启动虚拟机&#xff0c;在终端中执行if…

MySQL示例数据库(MySQL Sample Databases) 之 sakila数据库

文章目录 MySQL示例数据库(MySQL Sample Databases) 之 sakila数据库官方示例数据介绍sakila数据库sakila数据库安装sakila/sakila-schema.sql的脚本内容sakila的结构参考 MySQL示例数据库(MySQL Sample Databases) 之 sakila数据库 官方示例数据介绍 MySQL 官方提供了多个示…

Mysql存储json格式数据需要掌握的

目录 一、前言二、什么是 JSON三、Mysql当中json函数四、JSON值部分更新4.1.使用 Partial Updates 的条件4.2.如何在 binlog 中开启 Partial Updates4.3.关于 Partial Updates 的性能测试 五、如何对 JSON 字段创建索引六、mybatis取json类型的数据七、总结 一、前言 最近做的一…

[实训] 实验1-SPI数据传输基础实验(上)

目 录​​​​​​​ 一、实验目的 二、实验仪器及器件 三、实验内容及原理 四、实验步骤​​​​​​​ 五、实验测试数据表格记录 六、实验数据分析及处理 七、实验结论与感悟 一、实验目的 使用FPGA/ARM实现SPI数据传输实验&#xff1b;实现数据传输程序的编写、下载…

【项目原理】多点触摸屏驱动原理

一、屏幕介绍 ATK-7016 这款屏幕其实是由 TFT LCD触摸屏组合起来的。底下是 LCD 面板&#xff0c;上面是触摸面板&#xff0c;将两个封装到一起就成了带有触摸屏的 LCD 屏幕。电容触摸屏也是需要一个驱动 IC的&#xff0c;驱动 IC 一般会提供一个 I2C 接口给主控制器&#xff…

[实训] 实验1-SPI数据传输基础实验(下)

目录 五、实验测试数据表格记录 六、实验数据分析及处理 七、实验结论与感悟 五、实验测试数据表格记录 实验现象数码管显示见第四节图4.4&#xff0c;示波器测量结果见下列图片。 图5.1 RST、MOSI/MISO波形测量结果 图5.2 SCLK、MOSI/MISO波形测量结果 仅调整示波器波…

C生万物 | 剖析函数指针经典应用 —— 回调函数

不懂函数指针的老铁可以先看看这篇文章【指针函数与函数指针】&#xff0c;上车&#xff0c;准备出发&#x1f697; 文章目录 一、回调函数的概念二、为什么要使用回调函数&#xff1f;三、回调函数使用场景场景一&#xff1a;模拟计算器的加减乘除场景二&#xff1a;模拟qsort…

MySQL集群方案总结与方案原理

前言 在给自己做着玩的一个项目准备数据库集群&#xff0c;顺带自己大致系统复习并记录一下。 单节点mysql存在的常见问题 当数据量和并发量上去后&#xff0c;单节点数据库无法满足大并发时性能上的要求。单节点的MySQL无法满足高可用&#xff0c;数据库宕机或者意外中断等故障…

数据结构学习分享之双向链表详解

数据结构第四课 1.前言2. 结构分析3. 双链表的实现3.1 初始化结构3.2 初始化函数3.3 尾插函数3.4 尾删函数3.5 头插函数3.6 头删函数3.7 销毁链表3.8 其他函数 4. 缓存利用率5. 总结 1.前言 &#x1f493;博主CSDN:杭电码农-NEO&#x1f493;&#x1f389;&#x1f389;&#x…

Python(一) 基础二(语句、文件读写)

1.语句 1.1.if…elif…else 类似于java的if…else if…else语句 1.1.1.判断条件 比较运算符: 、>、<、<、>、!、is、is not、in、not in 1.1.2.和is的区别 list_1 [aaa, bbb] list_2 [aaa, bbb] print(list_1 list_2) #结果:True print(list_1 is list_2)…

async await

async await async await 都是修饰符&#xff0c;修饰函数的。 async/await一定是成对出现的。比如用async也没有什么太大意义。只要函数体中出现了await&#xff0c;则当前函数必须用async来修饰。 用async修饰的函数&#xff0c;相当于用promise包裹起来。其实相当于把同步修…

基于jeecgboot的OA日程安排开发(一)

日程安排也是OA里的一项重要功能&#xff0c;所以基于jeecgboot开发这个日程安排。 日程安排主要涉及以下几个方面&#xff1a; 1、数据库方面&#xff0c;主要是分日历与日程 日历可以分个人日历与工作日历&#xff0c;一般情况下&#xff0c;个人日历只给自己查看&#xff0…

2023-05-02 动态规划简介

动态规划简介 1 动态规划的基本概念 阶段、状态、决策、策略、状态转移方程 1) 阶段和阶段变量 将问题的全过程恰当地分成若干个相互联系的阶段闫氏DP分析法&#xff1a;对应f[i][j]的ij遍历时形成的所有f[i][j]阶段的划分一般根据时间和空间的自然特征去划分阶段的划分便于把…

Nginx原理解析

master和worker 当linux启动的时候&#xff0c;会有两个和nginx相关的进程&#xff0c;一个是master,一个是worker。 master如何工作 当客户端发送请求到nginx之后&#xff0c;master会接收到这个请求&#xff0c;然后通知所有的worker进程&#xff0c;此时&#xff0c;work…

【STL十六】函数对象:包装器(std::function)——绑定器(std::bind)——函数适配器

【STL十六】函数对象&#xff1a;包装器(std::function&#xff09;——绑定器&#xff08;std::bind&#xff09;——函数适配器 一、包装器(std::function&#xff09;1、简介2、头文件3、构造函数4、demo5、异常 二、绑定器&#xff08;std::bind&#xff09;1、简介2、头文…

Nessus漏洞扫描以及OpenSSH漏洞修复验证

主机IP地址资源kali192.168.200.1285GB内存/4CPUCentOS7.5192.168.200.1292GB内存/2CPU https://www.tenable.com/downloads/nessus?loginAttemptedtrue curl --request GET \--url https://www.tenable.com/downloads/api/v2/pages/nessus/files/Nessus-10.5.1-ubuntu1404_am…

云原生Istio案例实战

目录 1 Istio监控功能1.1 prometheus和grafana1.2 访问prometheus1.3 访问grafana 2 项目案例&#xff1a;bookinfo2.1 理解什么是bookinfo2.2 sidecar自动注入到微服务2.3 启动bookinfo2.4 通过ingress方式访问2.5 通过istio的ingressgateway访问2.5.1 确定 Ingress 的 IP 和端…