Hive 练习题解答

题目

在 Github 上面找了一些题目来练习
https://github.com/zzyb/Hive_interview-question

解答

answer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
 -- 第一道面试题
-- 编写Hive的HQL语句求出连续三天登陆的用户id
select distinct user_id
from (
select user_id,
lag(login_date,1) over (partition by user_id order by login_date) prev,
login_date now,
lead(login_date,1) over (partition by user_id order by login_date) next
from login_log) t where datediff(now,prev) = 1 and datediff(next,now)=1;

-- 第一道面试题
-- 编写Hive的HQL语句求出每 个店铺的当月销售额和累计到当月的总销售额

select name,mon,monMoney,accMonMoney
from(
select name,mon,sum(monmoney) over (partition by name,mon) monMoney,
sum(monmoney) over (partition by name order by mon) accMonMoney,
row_number() over (partition by name,mon order by mon) top
from fangwen2)t where top=1;

-- 第二道面试题
-- 编写Hive的HQL语句求出每个用户截止到每月为止的最大单月访问次数和累计到该月的总访问次数
select usr,mon,num,col1 monPv,col2 maxMonPv,col3 accMonPv from(
select usr,mon,num,sum(num) over (partition by usr,mon) col1,
max(num) over (partition by usr,mon) col2,
sum(num) over (partition by usr order by mon) col3,
row_number() over (partition by usr,mon order by mon) col4 from fangwen) t where col4=1;

select usr,mon,maxPv,totalPv from(
select usr,mon,num,
max(num) over (partition by usr,mon) maxPV,
sum(num) over (partition by usr order by mon) totalPv,
row_number() over (partition by usr,mon order by mon) top
from fangwen) t where top=1;


-- 第三道面试题
-- 编写Hive的HQL语句按照day和mac分组,求出每组的销量累计总和,追加到每条记录的后面
select day,mac,color,num,
sum(num) over (partition by day,mac)
from mac;


-- TopN
-- 第六道面试题

-- 1、求出每一年的最高温度(年份,最高温度)
select t.c_year,max(t.c_temp) from (
select year(from_unixtime(unix_timestamp(substr(line,0,8),'yyyyMMdd'))) c_year,substr(line,9,2) c_temp from wendu
) t group by t.c_year;

select dt,year(dt),temp
from(
select concat_ws('-',substring(line,0,4),substring(line,5,2),substring(line,7,2)) dt,
substring(line,9,2) temp,
row_number() over (partition by substring(line,0,4) order by substring(line,9,2) DESC) top
from wendu) subT where top=1;

-- 2、求出每一年的最高温度是那一天(日期, 最高温度)

select dt,temp
from(
select concat_ws('-',substring(line,0,4),substring(line,5,2),substring(line,7,2)) dt,
substring(line,9,2) temp,
row_number() over (partition by substring(line,0,4) order by substring(line,9,2) DESC) top
from wendu) subT where top=1;

select t.c_year,t.c_date,t.c_max from
(select
year(from_unixtime(unix_timestamp(substr(line,0,8),'yyyyMMdd'))) c_year,
from_unixtime(unix_timestamp(substr(line,0,8),'yyyyMMdd')) c_date,
row_number() over(partition by year(from_unixtime(unix_timestamp(substr(line,0,8),'yyyyMMdd'))) order by substr(line,9,2) DESC) as c_rank,
substr(line,9,2) c_max
from wendu) t where t.c_rank = 1;

-- 第四道面试题
-- 求出所有数学课程成绩 大于 语文课程成绩的学生的学号
-- 方法1 case when
select * from(
select sid,
max(case course when 'yuwen' then course end) yuwen,
max(case course when 'yuwen' then score end) yuwenScore,
max(case course when 'shuxue' then course end) shuxue,
max(case course when 'shuxue' then score end) shuxueScore,
max(case course when 'yingyu' then course end) yingyu,
max(case course when 'yingyu' then score end) yingyuScore
from chengji group by sid) t where t.shuxueScore > t.yuwenScore;

-- 方法2 join
select sid,t1score yuwen,t2score shuxue from(
select * from (
select sid,course,score t1score
from chengji
where course = 'yuwen'
) t1
join (
select sid,course,score t2score from chengji where course = 'shuxue'
) t2 on t1.sid = t2.sid) t3 where t3.t2score > t3.t1score;

-- 第五道面试题
-- id_course.id id_course.course
-- 1 a
-- 1 b
-- 1 c
-- 1 e
-- 2 a
-- 2 c
-- 2 d
-- 2 f
-- 3 a
-- 3 b
-- 3 c
-- 3 e
-- 转换为
-- id a b b c d e f
-- 1 1 1 1 1 0 1 0
-- 2 1 0 0 1 1 0 1
-- 3 1 1 1 1 0 1 0

select id,
max(case course when 'a' then 1 ELSE 0 end) a,
max(case course when 'b' then 1 ELSE 0 end) b,
max(case course when 'b' then 1 ELSE 0 end) b,
max(case course when 'c' then 1 ELSE 0 end) c,
max(case course when 'd' then 1 ELSE 0 end) d,
max(case course when 'e' then 1 ELSE 0 end) e,
max(case course when 'f' then 1 ELSE 0 end) f
from id_course group by id;

-- 第七道面试题
-- 1,huangbo,45,a-c-d-f
-- 2,xuzheng,36,b-c-d-e
-- 3,huanglei,41,c-d-e
-- 4,liushishi,22,a-d-e
-- 5,liudehua,39,e-f-d
-- 6,liuyifei,35,a-d-e
-- 求出每种爱好中,年龄最大的人
select id,name,maxAge,favor
from (
select id, name, max(age) over (partition by favor) maxAge, favor,
row_number() over (partition by favor order by age DESC) top
from aihao lateral VIEW explode(split(favors, '-')) t1 as favor
)t2 where top=1;
-- 列出每个爱好年龄最大的两个人,并且列出名字。
select id,name,maxAge,favor
from (
select id, name, max(age) over (partition by favor) maxAge, favor,
row_number() over (partition by favor order by age DESC) top
from aihao lateral VIEW explode(split(favors, '-')) t1 as favor
)t2 where top<=2;

-- 第十道面试题
-- 日期,产品id,产品当日收入,产品当日成本
-- 2018-03-01,a,3000,2500
-- 2018-03-01,b,4000,3200
-- 2018-03-01,c,3200,2400
-- 2018-03-01,d,3000,2500
-- 2018-03-02,a,3000,2500
-- 2018-03-02,b,1500,800
-- 2018-03-02,c,2600,1800
-- 2018-03-02,d,2400,1000
-- 2018-03-03,a,3100,2400
-- 2018-03-03,b,2500,2100
-- 2018-03-03,c,4000,1200
-- 2018-03-03,d,2500,1900
-- 2018-03-04,a,2800,2400
-- 2018-03-04,b,3200,2700
-- 2018-03-04,c,2900,2200
-- 2018-03-04,d,2700,2500
-- 2018-03-05,a,2700,1000
-- 2018-03-05,b,1800,200
-- 2018-03-05,c,5600,2200
-- 2018-03-05,d,1200,1000
-- 2018-03-06,a,2900,2500
-- 2018-03-06,b,4500,2500
-- 2018-03-06,c,6700,2300
-- 2018-03-06,d,7500,5000
-- 2018-04-01,a,3000,2500
-- 2018-04-01,b,4000,3200
-- 2018-04-01,c,3200,2400
-- 2018-04-01,d,3000,2500
-- 2018-04-02,a,3000,2500
-- 2018-04-02,b,1500,800
-- 2018-04-02,c,4600,1800
-- 2018-04-02,d,2400,1000
-- 2018-04-03,a,6100,2400
-- 2018-04-03,b,4500,2100
-- 2018-04-03,c,6000,1200
-- 2018-04-03,d,3500,1900
-- 2018-04-04,a,2800,2400
-- 2018-04-04,b,3200,2700
-- 2018-04-04,c,2900,2200
-- 2018-04-04,d,2700,2500
-- 2018-04-05,a,4700,1000
-- 2018-04-05,b,3800,200
-- 2018-04-05,c,5600,2200
-- 2018-04-05,d,5200,1000
-- 2018-04-06,a,2900,2500
-- 2018-04-06,b,4500,2500
-- 2018-04-06,c,6700,2300
-- 2018-04-06,d,7500,5000

-- 源数据3月份与4月份日利润相同,添加一条数据使其不同。
insert into goods values ('2018-04-07','d','5000','3000');

-- 1. 输出每个产品,在2018年期间,每个月的净利润,日均成本。
select d_month,profit,avgCost from (
select concat(year(dt),'-',month(dt)) d_month,name,income,cost,
(sum(income) over(partition by concat(year(dt),'-',month(dt))) -
sum(cost) over(partition by concat(year(dt),'-',month(dt)))) profit,
avg(cost) over(partition by concat(year(dt),'-',month(dt))) avgCost,
row_number() over (partition by concat(year(dt),'-',month(dt)) order by name) top
from goods where year(dt) = '2018') t_month where t_month.top=1;

-- 2. 输出每个产品,在2018年3月中每一天与上一天相比,成本的变化。
select
dt,cost,
(cost - LAG(cost,1,cost) over(partition by concat(year(dt),'-',month(dt)) order by dt))
from goods where concat(year(dt),'-',month(dt)) = '2018-3';

-- 3. 输出2018年4月,有多少个产品总收入大于22000元,必须用一句SQL语句实现,且不允许使用关联表查询、子查询。
select concat(year(dt),'-',month(dt)),name,sum(income) sumIncome
from goods where concat(year(dt),'-',month(dt)) = '2018-4'
group by name,concat(year(dt),'-',month(dt)) having sumIncome>22000;

-- 4. 输出2018年4月,总收入最高的那个产品,每日的收入,成本,过程使用over()函数。
select g.dt,maxT.name,maxT.maxIncome,g.income,g.cost from(
select name,totalIncome,max(totalIncome) over() maxIncome from(
select
dt,name,income,cost,
sum(income) over (partition by name) totalIncome
from goods where concat(year(dt),'-',month(dt)) = '2018-4') t limit 1
) maxT join goods g on maxT.name=g.name where concat(year(dt),'-',month(dt)) = '2018-4';



hive HQL 常用操作

资料

https://blog.csdn.net/u013411339/article/details/120795941

远程连接hive

https://blog.csdn.net/qq_44065303/article/details/105820435

服务端要开启 hiveserver2

建表方式

1
2
3
4
5
6
7
8
9
10
11
12
-- 1.正常建表
-- 建表后无数据
create table tableName(col1 int,col2 int);

-- 2.查询建表 as
-- 建表后有数据,数据为查询结果
-- 并不会带原表的分区(分区丢失),包扣一些字段的约束等
create table tableName as select * from tableA;

-- 3.结构建表 like
-- 建表后无数据,表结构从 tableA 中复制
create table tableName like tableA;

函数查询

1
2
3
4
5
6
7
8
9
10
11
12
-- 查看内置函数
SHOW FUNCTIONS;

-- 查看month相关的函数
SHOW FUNCTIONS LIKE '*month*';

-- 查看函数用法
DESC FUNCTION function_name;

-- 查看 add_months 函数的详细说明并举例
DESC FUNCTION EXTENDED add_months;

CTE

1
2
3
4
-- 公用表表达式
-- 创建一个临时结果集
with tableName as (select * from tableB)
select * from tableName;

时间转换函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
语法: unix_timestamp()
返回值: bigint
说明: 获得当前时区的UNIX时间戳
hive> select unix_timestamp() from tableName;
1616906976


语法: from_unixtime(bigint unixtime[, string format])
返回值: string
说明: 转化UNIX时间戳(从1970-01-01 00:00:00 UTC到指定时间的秒数)到当前时区的时间格式
hive> select from_unixtime(1616906976,'yyyyMMdd') from tableName;
20210328

语法: unix_timestamp(string date)
返回值: bigint
说明: 转换格式为"yyyy-MM-dd HH:mm:ss"的日期到UNIX时间戳。如果转化失败,则返回0
hive> select unix_timestamp('2021-03-08 14:21:15') from tableName;
1615184475

语法: unix_timestamp(string date, string pattern)
返回值: bigint
说明: 转换pattern格式的日期到UNIX时间戳。如果转化失败,则返回0
hive> select unix_timestamp('2021-03-08 14:21:15','yyyyMMdd HH:mm:ss') from tableName;
1615184475

语法: to_date(string timestamp)
返回值: string
说明: 返回日期时间字段中的日期部分。
hive> select to_date('2021-03-28 14:03:01') from tableName;
2021-03-28

语法: year(string date)
返回值: int
说明: 返回日期中的年。
hive> select year('2021-03-28 10:03:01') from tableName;
2021
hive> select year('2021-03-28') from tableName;
2021

日期函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
语法: datediff(string enddate, string startdate)
返回值: int
说明: 返回结束日期减去开始日期的天数。
hive> select datediff('2020-12-08','2012-05-09') from tableName;
213

语法: date_add(string startdate, int days)
返回值: string
说明: 返回开始日期startdate增加days天后的日期。
hive> select date_add('2020-12-08',10) from tableName;
2020-12-18

语法: date_sub (string startdate, int days)
返回值: string
说明: 返回开始日期startdate减少days天后的日期。
hive> select date_sub('2020-12-08',10) from tableName;
2020-11-28

窗口函数

窗口聚合函数

sum

1
2
3
4
5
-- 共4种用法
sum(...) over() -- 相当于对全表进行求和
sum(...) over(order by ...) -- 连续累积求和,排序,不分组
sum(...) over(partition by ...) -- 同组内所行求和,只分组不排序
sum(...) over(partition by ... order by ...) -- 在每个分组内,连续累积求和,分组+排序

partition by

partition by

order by

order by

窗口表达式

窗口表达式提供了一种控制行范围的能力如往前,往后n行

可以写多个列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- 默认从第一行到当前行
sum(...) over(partition by ... order by ...)
sum(...) over(partition by ... order by ... , ...) -- 按多列分区
sum(...) over(partition by ... order by ... rows between unbounded preceding and current row)

-- 向前3行至当前行
sum(...) over(partition by ... order by ... rows between 3 preceding and current row)

-- 向前3行,向后1行
sum(...) over(partition by ... order by ... rows between 3 preceding and 1 following)

-- 当前行到最后一行
sum(...) over(partition by ... order by ... rows between current row and unbounded following)

-- 第一行至最后一行,即分组内所有行
sum(...) over(partition by ... order by ... rows between unbounded preceding and unbounded following)

窗口排序函数

1
2
3
4
-- row_number家族,在每个分组中,为每行分配一个从1开始的唯一序号
row_number -- 不考虑重复
rank -- 考虑重复,挤占后续位置
dense_rank -- 考虑重复,不挤占后续位置
1
2
3
4
5
6
7
-- 窗口排序函数 ntile
将每个分组内的数据分为指定的若干个桶内,并且为每一个桶分配一个桶编号

select cookieid,createtime,pv
ntile(3) over(partition by cookieid order by createtime)
from website_pv_info
order by cookieid,createtime;

抽样函数

随机抽样 random

随机,但是速度慢

1
2
select * from website_pv_info order by rand() limit 2;
select * from website_pv_info distribute by rand() sort by rand() limit 2;

block 抽样

速度快,但是不随机

1
2
3
4
5
6
-- 按行数抽样
select * from website_pv_info tablesample (1 rows);
-- 根据数据大小百分比抽样
select * from website_pv_info tablesample (50 percent);
-- 根据数据大小抽样,支持b,k,m,g
select * from website_pv_info tablesample (1B);

bucket table 基于分桶表抽样

速度快+随机

tablesample(BUCKET x OUT OF y [ON colname])
tablesample

1
2
3
-- 根据整行数据进行抽样
select * from website_pv_info tablesample ( bucket 1 out of 2 on rand());

类型转换

1
2
3
4
5
6
7
8
9
-- CAST可以转换的类型
-- 1.隐式类型转换规则如下
-- (1)任何整数类型都可以隐式地转换为一个范围更广的类型,如 TINYINT 可以转换成 INT,INT 可以转换成 BIGINT。
-- (2)所有整数类型、FLOAT 和 STRING 类型都可以隐式地转换成 DOUBLE。
-- (3)TINYINT、SMALLINT、INT 都可以转换为 FLOAT。
-- (4)BOOLEAN 类型不可以转换为任何其它的类型。
CAST('1' AS INT) -- 可以正常执行
CAST('X' AS INT) -- 执行失败返回 NULL

concat 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
-- CONCAT 函数用于将多个字符串连接成一个字符串。
-- CONCAT(str1,str2,…)
SELECT CONCAT(id,',',name) AS con FROM info LIMIT 1;返回结果为
+----------+
| con |
+----------+
| 1,BioCyc |
+----------+

-- CONCAT_WS() 指定参数之间的分隔符
SELECT CONCAT_WS('_',id,name) AS con_ws FROM info LIMIT 1;
+----------+
| con_ws |
+----------+
| 1_BioCyc |
+----------+

case when

1
2
3
4
5
6
7
8
9
-- 简单 case
CASE sex
WHEN '1' THEN '男'
WHEN '2' THEN '女'
ELSE '其他' END
-- 搜索 case
CASE WHEN sex = '1' THEN '男'
WHEN sex = '2' THEN '女'
ELSE '其他' END

UDTF(explode)和侧视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- explode 
-- 接收 array 和 map 转换成多行
select explode(`array`(1,2,3,4,5));
-- Result:
-- col
-- 1
-- 2
-- 3
-- 4
-- 5
select explode(`map`("name","xxx",'sex','男','age','13'));
-- Result:
-- key value
-- name xxx
-- sex 男
-- age 13

-- 侧视图结合 explode
-- 侧视图语法
select ... from tableA lateral view UDTF(xxx) 表别名 as 列别名1,列别名2,列别名3;

行列转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
-- 多行转多列
-- 利用case when
-- 原表
-- students.id students.name students.subject students.score
-- 1 小明 语文 87
-- 2 张三 语文 27
-- 3 王五 语文 69
-- 4 李四 语文 99
-- 5 小明 数学 86
-- 6 马六 数学 33
-- 7 李四 数学 44
-- 8 小红 数学 50
-- 转换后
-- name chinese math
-- 小明 87 86
-- 小红 0 50
-- 张三 27 0
-- 李四 99 44
-- 王五 69 0
-- 马六 0 33

select name,
max(case subject when '语文' then score else 0 end) chinese,
max(case subject when '数学' then score else 0 end) math
from students group by name;

-- 多行转单列
-- 转换前
-- cookie.cookieid cookie.createtime cookie.pv
-- cookie1 2015-04-11 5
-- cookie1 2015-04-12 7
-- cookie1 2015-04-10 1
-- cookie1 2015-04-13 3
-- cookie1 2015-04-14 2
-- cookie1 2015-04-15 4
-- cookie1 2015-04-16 4
-- cookie2 2015-04-10 2
-- cookie2 2015-04-11 3
-- cookie2 2015-04-12 5
-- cookie2 2015-04-13 6
-- cookie2 2015-04-14 3
-- cookie2 2015-04-15 9
-- cookie2 2015-04-16 7
-- 转换后
-- cookieid createtimes pvs
-- cookie1 ["2015-04-10","2015-04-11","2015-04-12","2015-04-13","2015-04-14","2015-04-15","2015-04-16"] [1,5,7,3,2,4,4]
-- cookie2 ["2015-04-10","2015-04-11","2015-04-12","2015-04-13","2015-04-14","2015-04-15","2015-04-16"] [2,3,5,6,3,9,7]


select cookieid,collect_list(createtime) createtimes,collect_list(pv) pvs from cookie group by cookieid;
-- 其他函数
COLLECT_LIST(col) -- 多行合并成一行,不去重
COLLECT_SET(col) -- 多行合并成一行,将某字段的值进行去重汇总
CONCAT([string|col],[string|col],[string|col],....) -- 返回输入字符串连接后的结果,支持任意个输入字符串
CONCAT_WS('分隔符',[array|map]) -- 指定分隔符


-- 多列转多行
-- 主要使用 union 关键字
-- 转换前
-- rows2cols.col1 rows2cols.col2 rows2cols.col3 rows2cols.col4
-- a 1 2 3
-- b 4 5 6
-- 转换后
-- _u1.col1 _u1.col2 _u1.col3
-- a c 1
-- a d 1
-- a e 1
-- b c 4
-- b d 4
-- b e 4

select col1,'c' as col2,col2 as col3 from rows2cols
union all
select col1,'d' as col2,col2 as col3 from rows2cols
union all
select col1,'e' as col2,col2 as col3 from rows2cols;

-- 单列转多行
-- 转换前
-- aihao.id aihao.name aihao.age aihao.favors
-- 1 huangbo 45 a-c-d-f
-- 2 xuzheng 36 b-c-d-e
-- 3 huanglei 41 c-d-e
-- 4 liushishi 22 a-d-e
-- 5 liudehua 39 e-f-d
-- 6 liuyifei 35 a-d-e
-- 转换后
-- id name age favorslist
-- 1 huangbo 45 a
-- 1 huangbo 45 c
-- 1 huangbo 45 d
-- 1 huangbo 45 f
-- 2 xuzheng 36 b
-- 2 xuzheng 36 c
-- 2 xuzheng 36 d
-- 2 xuzheng 36 e
-- 3 huanglei 41 c
-- 3 huanglei 41 d
-- 3 huanglei 41 e
-- 4 liushishi 22 a
-- 4 liushishi 22 d
-- 4 liushishi 22 e
-- 5 liudehua 39 e
-- 5 liudehua 39 f
-- 5 liudehua 39 d
-- 6 liuyifei 35 a
-- 6 liuyifei 35 d
-- 6 liuyifei 35 e

select id,name,age,t.col1 as favorsList from aihao lateral VIEW explode(split(favors,'-')) t as col1;

-- lateral VIEW + explode

常见案例

查看前百分之N

1
2
3
4
5
6
7
8
9
10
11
/*
NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。注意:n必须为int类型
ntile(n)和where sorter = m 构成 n/m,如:ntile(2)和where sorted = 1 构成显示所有列的1/2
20% = 1/5 ==> ntile(5),where sorted = 1
*/
SELECT *
FROM (
SELECT name, orderdate, cost, NTILE(5) OVER (ORDER BY orderdate DESC) sorted
FROM business
) t
WHERE sorted = 1;

TOPN 问题

1
2
3
select * from (
select ROW_NUMBER() over(partition by ... order by ... DESC) as rank from tableName
) t where t.rank < 3;

与前一天相比

1
2
3
4
5
LAG(列名,前几行,'默认值')
LAG(name, 1)
LAG(name, 1,'default')
-- 表示取前一条记录的name的值。
-- LEAD()函数与此类似,不过它是查询某字段的后N条记录的值。

连续登录/连续问题

连续登录/连续问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
-- 原数据
1,2020-01-01
1,2020-01-02
1,2020-01-07
1,2020-01-08
1,2020-01-09
1,2020-01-10
2,2020-01-01
2,2020-01-02
2,2020-01-03
2,2020-01-04
3,2020-01-02
3,2020-01-03
3,2020-01-04

-- 两种方案
-- 1.自连接,构建笛卡尔积
-- 2. 窗口函数

-- 自连接
-- 两天的连续登录问题使用自连接比较好做,大于2天不适合用自连接
-- 1.自连接
select a.user_id a_id,a.login_date a_dt,
b.user_id b_id,b.login_date b_dt
from login_log a,login_log b;

-- 2.查找用户id相同并且时间差为1的记录
select *
from (
select a.user_id a_id,a.login_date a_dt,
b.user_id b_id,b.login_date b_dt
from login_log a,login_log b
) t where t.a_id=t.b_id and datediff(t.a_dt,t.b_dt)=1;
-- 提取id,并去重
select distinct t1.a_id
from (
select *
from (
select a.user_id a_id,a.login_date a_dt,
b.user_id b_id,b.login_date b_dt
from login_log a,login_log b
) t where t.a_id=t.b_id and datediff(t.a_dt,t.b_dt)=1) t1;


-- 窗口函数
-- 适合于连续N天的问题

select distinct user_id from (
select user_id,login_date,
date_add(login_date,4-1) as nextday,
lead(login_date,4-1) over (partition by user_id order by login_date) as nextlogin
from login_log
) t where nextday = nextlogin;

-- nextday,手动算出 N 天后的时间
-- nextlogin,向下取 N 行进行验证


级联/累加求和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
-- 编写Hive的HQL语句求出每个用户截止到每月为止的最大单月访问次数和累计到该月的总访问次数
-- 原表
usr,mon,num
A,2015-01,5
A,2015-01,15
B,2015-01,5
A,2015-01,8
B,2015-01,25
A,2015-01,5
A,2015-02,4
A,2015-02,6
B,2015-02,10
B,2015-02,5
A,2015-03,16
A,2015-03,22
B,2015-03,23
B,2015-03,10
B,2015-03,11
-- 两种方法
-- 1.group by 加自连接
-- 2.窗口函数

-- 1.group by 加自连接
-- 过于复杂,不写了
-- https://www.bilibili.com/video/BV1L5411u7ae?p=126

-- 方法2
-- 窗口函数

-- 关键点是
sum(num) over (partition by usr order by mon) accPV

with t as (
select usr,mon,num,
row_number() over (partition by usr,mon order by num DESC) top,
sum(num) over (partition by usr order by mon) accPV
from fangwen
)select usr,mon,num,accPV from t where top=1;