背景
SQL中JOIN子句是用于把來自兩個或多個表的數(shù)據(jù)連接起來,在這個過程中可能會添加一些過濾條件,。昨天有小伙伴問,,如下圖的這兩種SQL寫法查詢結(jié)果是否會一樣,?(好像這是某一年阿里的面試題)
這個問題提出來以后,,多數(shù)小伙伴的回答是:查詢結(jié)果應(yīng)該是一樣的吧,,只是查詢效率不一樣。我當(dāng)時的回答是,,在Inner Join時這兩種情況返回的結(jié)果是一樣的,,在Left,、Right等情況時結(jié)果不一樣,。
案例
1、創(chuàng)建測試數(shù)據(jù)庫和表并且插入用戶測試的數(shù)據(jù),。
-- 創(chuàng)建數(shù)據(jù)庫
CREATE DATABASE ods_study_1;
USE ods_study_1;
-- 創(chuàng)建表
CREATE TABLE ods_study_1.ods_study_join_a
(
study_id_a int
);
CREATE TABLE ods_study_1.ods_study_join_b
(
study_id_b int,
study_channel varchar(255)
);
-- 插入數(shù)據(jù)
INSERT INTO ods_study_1.ods_study_join_a(study_id_a) VALUES(1),(2),(3),(4),(5)
INSERT INTO ods_study_1.ods_study_join_b(study_id_b,study_channel) VALUES(1,'weixin'),(2,'zhihu'),(2,'zhihu'),(3,'toutiao');
2,、查看一下原始的數(shù)據(jù):
結(jié)果驗證
將上面的兩個表Inner Join和Left Join,過濾條件分別放在on和where中,。
1、Inner Join時
SELECT
*
FROM
ods_study_1.ods_study_join_a A
Inner JOIN
ods_study_1.ods_study_join_b B
ON (A.study_id_a = B.study_id_b AND B.study_channel='weixin')
返回結(jié)果:
SELECT
*
FROM
ods_study_1.ods_study_join_a A
Inner JOIN
ods_study_1.ods_study_join_b B
ON (A.study_id_a = B.study_id_b )
WHERE B.study_channel='weixin'
返回結(jié)果:
結(jié)論:Inner Join時過濾條件放在on和where中返回結(jié)果一致,。
2、Left Join時
SELECT
*
FROM
ods_study_1.ods_study_join_a A
LEFT JOIN
ods_study_1.ods_study_join_b B
ON (A.study_id_a = B.study_id_b AND B.study_channel='weixin')
返回結(jié)果:
SELECT
*
FROM
ods_study_1.ods_study_join_a A
LEFT JOIN
ods_study_1.ods_study_join_b B
ON (A.study_id_a = B.study_id_b )
WHERE B.study_channel='weixin'
返回結(jié)果:
結(jié)論:Left Join時過濾條件放在on和where中返回結(jié)果不一致,。
原因分析
可以這么理解,,當(dāng)兩張表在Left Join時,會生成一張連接臨時表,,然后再將這張連接臨時表返回給用戶,。
在On的情況下,是在生成臨時表時起作用,,但由于Left Join的性質(zhì),,就是他不管On里面的過濾條件是否為真,都會返回左表里的記錄,。對于不滿足條件的記錄,,右表字段全部是NULL。
在Where的情況下,,是在臨時表生成好以后起作用,在對臨時表進行過濾,。此時,,只要條件不為真的行,全部都過濾掉了,。