HiveSQL题——用户连续登陆

目录

一、连续登陆

[1.1 连续登陆3天以上的用户](#1.1 连续登陆3天以上的用户)

[0 问题描述](#0 问题描述)

[1 数据准备](#1 数据准备)

[2 数据分析](#2 数据分析)

[3 小结](#3 小结)

[1.2 每个用户历史至今连续登录的最大天数](#1.2 每个用户历史至今连续登录的最大天数)

[0 问题描述](#0 问题描述)

[1 数据准备](#1 数据准备)

[2 数据分析](#2 数据分析)

[3 小结](#3 小结)

[1.3 每个用户连续登录的最大天数(间断也算)](#1.3 每个用户连续登录的最大天数(间断也算))

[0 问题描述](#0 问题描述)

[1 数据准备](#1 数据准备)

[2 数据分析](#2 数据分析)

[3 小结](#3 小结)


一、连续登陆

1.1 连续登陆3天以上的用户

0 问题描述

查询连续登陆3天以上的用户(字节面试题)

1 数据准备

sql 复制代码
create table if not exists  table1  (id int comment '用户id', `date` string comment'用户登录时间');

insert overwrite table table1 values
(1,'2019-01-01 19:28:00'),
(1,'2019-01-02 19:53:00'),
(1,'2019-01-03 22:00:00'),
(1,'2019-01-05 20:55:00'),
(1,'2019-01-06 21:58:00'),
(2,'2019-02-01 19:25:00'),
(2,'2019-02-02 21:00:00'),
(2,'2019-02-04 22:05:00'),
(2,'2019-02-05 20:59:00'),
(2,'2019-02-06 19:05:00'),
(3,'2019-03-04 21:05:00'),
(3,'2019-03-05 19:10:00'),
(3,'2019-03-06 19:55:00'),
(3,'2019-03-07 21:05:00');

2 数据分析

sql 复制代码
select
    distinct id
from (select
          id,
          diff
      from (
               select
                   id,
                   date_sub(dt, row_number()over (partition by id order by dt)) diff
               from (  --- 同一个用户一天可能登陆多次,所以,先去重
                        select
                            id,
                            date_format(`date`,'yyyy-MM-dd') as dt
                        from table1
                        -- current_date() 获取当前的年月日
                        where date_format(`date`,'yyyy-MM-dd') between date_sub(current_date(),7) and current_date()
                        group by id, date_format(`date`,'yyyy-MM-dd')
                    ) tmp1
           ) tmp2
      group by id, diff
      having count(1) >= 3) tmp3;

3 小结

"连续登陆"类型的解题思路:

(1)计算 date_sub(login_date,row_number() over (user_id oder by login_date)) diff;

(2)group by user_id,diff 分组;

(3)count(1) >= 3天的用户就是连续登陆3天及以上的用户

1.2 每个用户历史至今连续登录的最大天数

0 问题描述

查询每个用户历史至今连续登录的最大天数

1 数据准备

sql 复制代码
create table if not exists  table1  (id int comment '用户id', `date` string comment'用户登录时间');

insert overwrite table table1 values
(1,'2019-01-01 19:28:00'),
(1,'2019-01-02 19:53:00'),
(1,'2019-01-03 22:00:00'),
(1,'2019-01-05 20:55:00'),
(1,'2019-01-06 21:58:00'),
(2,'2019-02-01 19:25:00'),
(2,'2019-02-02 21:00:00'),
(2,'2019-02-04 22:05:00'),
(2,'2019-02-05 20:59:00'),
(2,'2019-02-06 19:05:00'),
(3,'2019-03-04 21:05:00'),
(3,'2019-03-05 19:10:00'),
(3,'2019-03-06 19:55:00'),
(3,'2019-03-07 21:05:00');

2 数据分析

sql 复制代码
select
    id,
    max(cnt) as days
from (
         select
             id,
             count(1) as cnt
         from (
                  select
                      id,
                      `date`,
                      date_sub(`date`, row_number() over (partition by id order by `date`)) diff
                  from (--用户在同一天可能登录多次,需要去重
                           select
                               id,
                               date_format(`date`, 'yyyy-MM-dd') as `date`
                           from table1
                           group by id, date_format(`date`, 'yyyy-MM-dd')
                       ) tmp1
              ) tmp2
         group by id, diff
     ) tmp3
group by id;

3 小结

"连续登陆"类型的解题思路:

(1)计算 date_sub(login_date,row_number() over (user_id oder by login_date)) diff;

(2)group by user_id,diff 分组;

(3)max(cnt)得到就是每个用户历史至今连续登陆的 最大天数。

1.3 每个用户连续登录的最大天数(间断也算)

0 问题描述

统计各用户最长的连续登录天数,间断一天也算作连续。例如:一个用户在1,3,5,6号登录,则视为连续6天登录。

1 数据准备

sql 复制代码
create table if not exists  table1  (id int comment '用户id', `date` string comment'用户登录时间');

insert overwrite table table1 values
(1,'2019-01-01 19:28:00'),
(1,'2019-01-02 19:53:00'),
(1,'2019-01-03 22:00:00'),
(1,'2019-01-05 20:55:00'),
(1,'2019-01-06 21:58:00'),
(2,'2019-02-01 19:25:00'),
(2,'2019-02-02 21:00:00'),
(2,'2019-02-04 22:05:00'),
(2,'2019-02-05 20:59:00'),
(2,'2019-02-06 19:05:00'),
(3,'2019-03-04 21:05:00'),
(3,'2019-03-05 19:10:00'),
(3,'2019-03-06 19:55:00'),
(3,'2019-03-07 21:05:00');

2 数据分析

方式一:间断的那一天,构造array数组,利用炸裂函数进行补全,然后按照"用户连续登陆"的思路来做。

sql 复制代码
select
    id,
    max(cnt) as days
from (
         select
             id,
             diff,
             count(1) as cnt
         from (
                  select
                      id,
                      login_date,
                      next_login_date,
                      arr,
                      new_login_date,
                      date_sub(new_login_date, row_number() over (partition by id order by new_login_date)) diff
                  from (
                           select
                               id,
                               login_date,
                               next_login_date,
                               arr,
                               new_login_date
                           from (
                                    select
                                        id,
                                        login_date,
                                        next_login_date,
                                     --间断的那一天,构造array数组,利用炸裂函数进行补全
                                        if(
                                                datediff(next_login_date, login_date) = 2,
                                                array(login_date, date_add(login_date, 1)),
                                                array(login_date)
                                            ) as arr

                                    from (
                                             select
                                                 id,
                                                 login_date,
                                                 --窗口函数 lead(向后取n行)
                                                 --lead(column1,n,val)over(partition by column2 order by column3) 查询当前行的后边第n行数据,如果没有就为null
                                                 lead(login_date, 1, '9999-12-31')
                                                      over (partition by id order by login_date) next_login_date
                                             from (--用户在同一天可能登录多次,需要去重
                                                      select
                                                          id,
                                                          date_format(`date`, 'yyyy-MM-dd') as login_date
                                                      from table1
                                                      group by id, date_format(`date`, 'yyyy-MM-dd')
                                                  ) tmp1
                                         ) tmp2
                                ) tmp3
                                    lateral view explode(arr) tmp as new_login_date
                       ) tmp4
              ) tmp5
         group by id, diff
     ) tmp6
group by id;
复制代码
方式二:对用户多段stage的连续登陆进行划分,思路类似:会话划分
sql 复制代码
select
    id,
    max(diff) as days
from (
         select
             id,
             stage,
             datediff(max(login_date), min(login_date)) + 1 as diff
         from (
                  select
                      id,
                      login_date,
                      -- 思路类似:会话划分,字符串拼接得到stage
                      concat(id, '-', sum(start_point)
                                          over (partition by id order by login_date rows between unbounded preceding and current row )) stage
                  from (
                           select
                               id,
                               login_date,
                                --间隔一天也算连续,所以差值大于2的数据打上标签
                               if(datediff(login_date, last_login_date) > 2, 1, 0) start_point
                           from (
                                    select
                                        id,
                                        login_date,
                                        --窗口函数 lag(向前取n行)
                                        --lag(column1,n,val)over(partition by column2 order by column3) 查询当前行的前边第n行数据,如果没有就为null
                                        lag(login_date, 1, '1970-01-01')
                                            over (partition by id order by login_date) as last_login_date
                                    from (
                                             select
                                                 id,
                                                 date_format(`date`, 'yyyy-MM-dd') as login_date
                                             from table1
                                             group by id, date_format(`date`, 'yyyy-MM-dd')
                                         ) tmp1
                                ) tmp2
                       ) tmp3
              ) tmp4
         group by id, stage
     ) tmp5
group by id;

3 小结

"间断连续"类型的解题思路:

(1)构造array数组;

(2)炸裂函数+ 侧写视图 : lateral view +explode将一行变多行,补全间断的那几天

(3)补全后之后就按照"连续登陆"的情景进行处理

  • 计算 date_sub(login_date,row_number() over (user_id oder by login_date)) diff;
  • group by user_id,diff 分组;
  • max(cnt)得到就是每个用户历史至今连续登陆的最大天数。
相关推荐
TechEdu2026066 分钟前
[计算机科学]大数据硬件架构与软件架构概览
大数据·计算机科学
爱莉希雅&&&12 分钟前
elasticsearch+kibana+logstash+filebeat链路部署流程
大数据·elasticsearch·搜索引擎·kibana·logstash·filebeat
FII工业富联科技服务28 分钟前
从灯塔工厂到AI Factory新模式:AI正在重构制造业的四大核心能力
大数据·运维·人工智能·重构·ar·制造
小五传输29 分钟前
自主可控建设指南:Serv-u替代方案,实现平滑迁移业务不中断
大数据·运维·安全
Spey_Events32 分钟前
【核心议题发布】聚焦深度维修与 AI 智慧革新!2026中国民用航空维修智造展——议题重磅发布!
大数据·人工智能
czzxxxxxx41 分钟前
创客匠人AI智能体:知识付费从“重人力”走向“自动化”的拐点
大数据·人工智能
大大大大晴天1 小时前
Hudi技术内幕:Clustering原理与实践
大数据
ZKNOW甄知科技1 小时前
燕千云深度集成飞书:以AI之力,开启无感IT运维体验
大数据·运维·网络·数据库·人工智能·低代码·集成学习
京和动物医院·总院1 小时前
2026年未央区宠物医院:如何挑选最适合您爱宠的健康守护者
大数据·人工智能·python
商业模式源码开发1 小时前
2026年GEO优化全解析:生成式引擎优化如何重构企业流量与品牌护城河
大数据·人工智能·ai