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)得到就是每个用户历史至今连续登陆的最大天数。
相关推荐
喝醉酒的小白1 小时前
ES 集群 A 和 ES 集群 B 数据流通
大数据·elasticsearch·搜索引擎
炭烤玛卡巴卡2 小时前
初学elasticsearch
大数据·学习·elasticsearch·搜索引擎
it噩梦2 小时前
es 中使用update 、create 、index的区别
大数据·elasticsearch
天冬忘忧2 小时前
Flink优化----数据倾斜
大数据·flink
李昊哲小课2 小时前
deepin 安装 zookeeper
大数据·运维·zookeeper·debian·hbase
筒栗子3 小时前
复习打卡大数据篇——Hadoop MapReduce
大数据·hadoop·mapreduce
金州饿霸3 小时前
Hadoop集群(HDFS集群、YARN集群、MapReduce计算框架)
大数据·hadoop·hdfs
lucky_syq3 小时前
Spark和MapReduce之间的区别?
大数据·spark·mapreduce
LonelyProgramme3 小时前
Flink定时器
大数据·flink
lucky_syq4 小时前
Hive SQL和Spark SQL的区别?
hive·sql·spark