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);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章