HiveSQL:看这里!一看就懂的连接查询及案例

1、学习目标

1、掌握HQL中的各种连接及其组合使用
2、掌握数据分析中业务指标思路转换的技巧

2、表连接

(1)inner join

多表内连接,取公共部分
表1:user_list_1
在这里插入图片描述
表2:user_list_2
在这里插入图片描述
找出既在user_list_1也在user_list_2的用户:

SELECT *
FROM user_list_1 a
JOIN user_list_2 b
ON a.user_id=b.user_id;

inner join 中inner可以省略
注意:

  • 表连接时,必须进行重命名
  • on后面使用的连接条件必须起到唯一键值的作用
  • 连接前注意去重,提高效率
  • inner可省略不写,效果一样

练习:
需求1:某年度对用户满意度进行调研分析,找出目标人群
思考:对用户的满意度我们可以分析用户购买又退款的用户。挑选2019年进行分析。

SELECT user_name
FROM
(SELECT distinct user_name
FROM user_trade
WHERE year(dt)=2019)a
JOIN
(SELECT distinct user_name
FROM user_refund
WHERE year(dt)=2019)b
on a.user_name=b.user_name;

注意:一定要先去重,再做表连接,养成良好习惯

需求2:用户忠诚度类项目的调研分析,找出目标人群
思考:考察用户的忠诚度,我们可以选择查看用户连续两年都有购买商品的记录。
在2017年和2018年都购买的用户。

SELECT a.user_name
FROM
(SELECT distinct user_name
FROM user_trade
WHERE year(dt)=2017)a
JOIN
(SELECT distinct user_name
FROM user_trade
WHERE year(dt)=2018)b
on a.user_name=b.user_name;			

在这里插入图片描述
需求3:高忠诚度用户的匹配分析,用以生成心路历程类报表推送给用户,
找出目标人群
思考:查询在2017年、2018年、2019都有交易的用户
第一种写法:

SELECT distinct a.user_name
FROM trade_2017 a
JOIN trade_2018 b on a.user_name=b.user_name		
JOIN trade_2019 c on b.user_name=c.user_name;		

第二种写法:

SELECT a.user_name
FROM
(SELECT distinct user_name
FROM trade_2017)a
JOIN
(SELECT distinct user_name
FROM trade_2018)b on a.user_name=b.user_name
JOIN
(SELECT distinct user_name
FROM trade_2019)c on b.user_name=c.user_name;

在表的数据量很大的时候,推荐第二种写法。
这里 select a.user_name或者b.user_name或者c.user_name都可以,因为join是取表的交集,所以不管取哪个表的这个字段都是一样的结果。

(2)left /right join

left join:进行左连接后,以左边的表1为全集,返回能够匹配上的右边表2的匹配结left果,没有匹配上的则显示NULL。
right join:以右边的表为全集,返回能够匹配上的右表的匹配结果,没有
匹配上的则显示NULL。
但其完全可以由left join改写出同样的结果,所以较少使用。

我们对上面的表1和表2进行左连接后看看会发生什么?

SELECT *
FROM user_list_1 a
LEFT JOIN user_list_2 b
ON a.user_id=b.user_id;

在这里插入图片描述
如何取出,在user_list_1表中但是不在user_list_2的用户?

SELECT a.user_id,
a.user_name
FROM user_list_1 a LEFT JOIN user_list_2 b
ON a.user_id=b.user_id
WHERE b.user_id is null;

在这里插入图片描述
练习:
需求4:无退款服务类用户的定位分析,用以发送服务判断类用户调研。
思考:无退款服务我们直接查询某一年购买过但是没有退款用户的记录。
在2019年购买,但是没有退款的用户。

SELECT a.user_name
FROM
(SELECT distinct user_name
FROM user_trade
WHERE year(dt)=2019)a
LEFT JOIN
(SELECT distinct user_name
FROM user_refund
WHERE year(dt)=2019)b on a.user_name=b.user_name
WHERE b.user_name is null;

需求5:对重点客户的学历进行调研分析,观察其分布情况。
在2019年购买用户的学历分布。

SELECT b.education,
count(distinct a.user_name)
FROM
(SELECT distinct user_name
FROM user_trade
WHERE year(dt)=2019)a
LEFT JOIN
(SELECT user_name,
get_json_object(extra1, '$.education') as
education
FROM user_info)b
on a.user_name=b.user_name
GROUP BY b.education;

SQL解析:
这里的extra1是一个json数据,用$. 取数据即可。
get_json_object 就是获取json字符串。
在这里插入图片描述
需求6:老客户召回计划,匹配到目标人群。
思考:老客户的召回计划,也就是说之前使用过并且购买过的用户,在近期或者更长时间没有购买或者使用的用户。
在2017和2018年都购买,但是没有在2019年购买的用户。

SELECT a.user_name
FROM
(SELECT distinct user_name
FROM trade_2017)a
JOIN
(SELECT distinct user_name
FROM trade_2018)b on a.user_name=b.user_name
LEFT JOIN
(SELECT distinct user_name
FROM trade_2019)c on b.user_name=c.user_name
WHERE c.user_name is null;

这里 a.user_name换成b.user_name也可以。

(3)full join

首先,我们看下对上面的表1和表2全连接后会出现什么?

SELECT *
FROM user_list_1 a FULL JOIN user_list_2 b ON
a.user_id=b.user_id;

FULL OUTER JOIN关键字只要左表和左表和右表其中一个表中存在匹配,则返回行。
FULL OUTER JOIN 关键字结合了LEFT JOIN和RIGHT JOIN 的结果。

user_list_1和user_list_2的所有用户:

SELECT coalesce(a.user_name,b.user_name)
FROM user_list_1 a FULL JOIN user_list_2 b
on a.user_id=b.user_id;

结果:
在这里插入图片描述

coalesce函数

coalesce函数:将空值替换成其他值,返回第一个非空值
coalesce(expression_1,expression_2,…,expression_n)
依次参考各参数表达式,遇到非null值即停止并返回该值。如果所有的表达式都是空值,最终将返回一个空值。

(4)union all

联合所有。

表1:user_list_1
在这里插入图片描述
表3:user_list_3
在这里插入图片描述
举例:
将user_list_1和user_list_3合并在一起:

SELECT user_id,
user_name
FROM user_list_1
UNION ALL
SELECT user_id,
user_name
FROM user_list_3 ;

在这里插入图片描述

注意:union all时
字段名称必须一致
字段顺序必须一致
没有连接条件

练习:
需求7:对近几年的交易进行分析,评估平台的价值。
在这里插入图片描述
查询2017年和2019年有交易的所有用户数。
写法一:

SELECT count(distinct a.user_name),
count(a.user_name)
FROM
(
SELECT user_name
FROM trade_2017
UNION ALL
SELECT user_name
FROM trade_2018
UNION ALL
SELECT user_name
FROM trade_2019)a;

在这里插入图片描述
写法二:

SELECT count(distinct a.user_name),
count(a.user_name)
FROM
(
SELECT user_name
FROM trade_2017
UNION
SELECT user_name
FROM trade_2018
UNION
SELECT user_name
FROM trade_2019)a;

在这里插入图片描述
从以上两个不同的写法中,我们可以看到 union 会在连接后进行去重的操作。

union all和union的区别

我们看下 union all 和 union 的区别
在这里插入图片描述
注意:如果表很大时推荐先去重再进行union all

需求8-1:对某年度的客户交易价值进行分析 。
实现2019年每个用户的支付和退款金额汇总。

SELECT a.user_name user_name,
sum(a.pay_amount) sum_pay_amount,
sum(a.refund_amount) sum_refund_amount
FROM
(
SELECT user_name,
sum(pay_amount) as pay_amount,
0 as refund_amount
FROM user_trade
WHERE year(dt)=2019
GROUP BY user_name
UNION ALL
SELECT user_name,
0 as pay_amount,
sum(refund_amount) as refund_amount
FROM user_refund
WHERE year(dt)=2019
GROUP BY user_name
)a
GROUP BY a.user_name
limit 6;

在这里插入图片描述
如何用full join来实现该题目?

SELECT coalesce(a.user_name,b.user_name) user_name,
a.pay_amount sum_pay_amount,
b.refund_amount sum_refund_amount
FROM
(SELECT user_name,
sum(pay_amount) as pay_amount
FROM user_trade
WHERE year(dt)=2019
GROUP BY user_name)a
FULL JOIN
(SELECT user_name,
sum(refund_amount) as refund_amount
FROM user_refund
WHERE year(dt)=2019
GROUP BY user_name)b
on a.user_name=b.user_name
limit 6;

在这里插入图片描述
可以看到两种写法的结果差异,没有退款的人,退款金额显示为null
如果用第二种写法,如何把NULL都变成0呢?

SELECT coalesce(a.user_name,b.user_name),
if(a.pay_amount is null,0,a.pay_amount),
if(b.refund_amount is null,0,b.refund_amount)
FROM
(SELECT user_name,
sum(pay_amount) as pay_amount
FROM user_trade
WHERE year(dt)=2019
GROUP BY user_name)a
FULL JOIN
(SELECT user_name,
sum(refund_amount) as refund_amount
FROM user_refund
WHERE year(dt)=2019
GROUP BY user_name)b
on a.user_name=b.user_name;

需求8-2:对某年度的重点客户交易价值进行分析。
查询2019年每个支付用户的支付金额和退款金额。

SELECT a.user_name,
a.pay_amount,
b.refund_amount
FROM
(SELECT user_name,
sum(pay_amount) as pay_amount
FROM user_trade
WHERE year(dt)=2019
GROUP BY user_name)a
LEFT JOIN
(SELECT user_name,
sum(refund_amount) as refund_amount
FROM user_refund
WHERE year(dt)=2019
GROUP BY user_name)b
on a.user_name=b.user_name;

练习一下:
需求9-1:对沉默用户的年龄段进行分析,用以部署活动来刺激其消费。
思考:沉默用户我们可以考虑是用户激活后再没使用过(支付过)。
查询首次激活时间在2017年,但是一直没有支付的用户年龄段分布。

SELECT a.age_level,
count(a.user_name)
FROM
(SELECT user_name,
case when age<20 then '20岁以下'
when age>=20 and age<30 then '20-30岁'
when age>=30 and age<40 then '30-40岁'
else '40岁以上' end as age_level
FROM user_info
WHERE year(firstactivetime)=2017)a
LEFT JOIN
(SELECT distinct user_name
FROM user_trade
WHERE dt>'0')b
on a.user_name=b.user_name
WHERE b.user_name is null
GROUP BY a.age_level;

需求9-2:对活跃用户的激活时间段进行分析,用以部署活动来刺激其消费。
实现2018、2019年交易的用户,其激活时间段分布。

SELECT hour(firstactivetime),
count(a.user_name)
FROM
(SELECT user_name
FROM trade_2018
UNION
SELECT user_name
FROM trade_2019)a
LEFT JOIN user_info b
on a.user_name=b.user_name
GROUP BY hour(firstactivetime);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章