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)得到就是每个用户历史至今连续登陆的最大天数。
相关推荐
ZHOU_WUYI4 分钟前
Apache Spark 集群部署与使用指南
大数据·spark·apache
爱看科技16 分钟前
科技新突破!微美全息(NASDAQ:WIMI)研发保留运动想象脑机接口“方差密钥”技术
大数据·人工智能·科技
中科岩创25 分钟前
青海某公路水渠自动化监测服务项目
大数据·人工智能·物联网
武子康33 分钟前
大数据-131 Flink CEP 实战 24 小时≥5 次交易 & 10 分钟未支付检测 案例附代码
大数据·后端·flink
Likeadust1 小时前
新版视频直播点播平台EasyDSS用视频破局,获客转化双提升
大数据·音视频
Aurora_eye2 小时前
记录之Ubuntu22.4虚拟机及hadoop为分布式安装
大数据·hadoop·分布式
Kay_Liang2 小时前
大语言模型如何精准调用函数—— Function Calling 系统笔记
java·大数据·spring boot·笔记·ai·langchain·tools
啊吧怪不啊吧2 小时前
SQL之参数类型讲解
数据库·sql
链上日记3 小时前
AIOT定义Web3健康新纪元:从智能硬件到健康金融
大数据
一人の梅雨3 小时前
大麦网关键词列表接口的产业级实现:从演出聚合到市场趋势预测的全维度技术方案
大数据·数据库·人工智能