深入理解SQL表連線(join)

2021-10-09 20:01:58 字數 2991 閱讀 4751

關聯式資料庫中最重要的兩個概念,當屬表連線和聚合。表連線將一條資料分開成多條,表聚合將多條合成一條。這一分一合,形成了關聯式資料庫強大的邏輯表達能力,這篇文章講表連線,關於聚合請移步:深入理解sql分組聚合

「內連線、外連線、左外連線、右外連線、全連線、交叉連線、自然連線」,這麼多種連線方式,你是不是已經暈了?一般的教科書都是從集合論及關係代數入手,搬出一大堆晦澀難懂的名詞,讀時好像懂了,但是過一段時間還是分不清楚。

其實要理解這些連線方式,你只需要記住一種連線「笛卡爾積」就可以了。也就是說,所有的其它連線方式,無非是在笛卡爾積的基礎上,要麼篩選掉一些記錄、要麼增加一些記錄。

笛卡爾積是什麼?想必大家都知道,它往往以負面形象出現,因為大家無時無刻被告知,在運算元據庫時要避開它。雖然熟視無睹,但還是解釋一下:它是指兩個表連線時,左表的每行記錄與右表的每行記錄均連線,那麼返回的記錄數是兩表記錄數的乘積。

其實笛卡爾積又稱交叉連線、直積,一般叫它笛卡爾積呢,為什麼呢?因為這樣叫顯得更高大上嘛!

言歸正傳,下面我們用笛卡爾積,稍做「加減法」,得出其它連線方式:

【笛卡爾積】

select * from a, b

這種不帶where條件的查詢結果,就是笛卡爾積,一般它會返回很多條記錄。

【內連線】

select * from a, b where a.id = b.id

上面這種語句,可能是日常工作中用得最多的,其實它就叫內連線。也就是說資料庫預設使用內連線方式。它可以看作是先將a,b兩表記錄兩兩連線,然後再按where條件後面的條件,去除不符合條件的記錄,所以:

內連線 = 笛卡爾積 - 不滿足where條件的

【左外連線】

select * from a leftjoin b on a.id=b.id

左外連線是指在內連線的基礎上,還要滿足,左表的記錄必須出現在結果中,也就是如果左表的某一條記錄,未出現在結果集中,那麼要強制將該條記錄放到結果集中,但是結果集的列是即包含了a表也包含了b表的,那b表的那些列怎麼填呢?那還能樣呢,所以只能都填null了。所以:

左外連線 = 笛卡爾積 - 不滿足on條件的 + 缺失的左表記錄

【右外連線】

select a right join b on a.id=b.id

同理左外連線,只是a,b表交換一下罷了。

【全外連線】

mysql不直接支援全外連線,但可以通過union左外連線及右外連線的記錄來實現

select a left join b on a.id=b.id

union all

select a right join b on a.id=b.id

這個很好理解,左外連線會補上缺失的左表記錄,那麼全外連線會補上左右表缺失的記錄,所以:

全外連線 = 笛卡爾積 - 不滿足on條件的 + 缺失的左表記錄 + 缺失的右表記錄

【自然連線】

select a natural join b

這種連線方式我在工作中從來沒有用過,其實它也很簡單,它就是在內連線的基礎上多了兩個約定:

1)、a,b兩表中存在相同的列,大家看sql中沒有where,它就是按相同的列名來連線的;

2)、返回的結果集中會去掉重複的列名;

正是因為它會預設按相同的列名進行連線,且會排除那些重複無用的列,所以它才會被叫做「自然」吧。所以:

自然連線 = 笛卡爾積 - 不滿足條件的

* 只是條件不用直接寫出來,條件是兩表的同名字段的值相等,且結果會去掉重複的列

+【補充】

1)、外連線不是一種特定的連線方式,它是左外連線、右外連線、全外連線的統稱,見上面內容;

2)、左外連線、右外連線、全外連線都可以把「外」字省略掉。所以左連線=左外連線、右連線=右外連線、全連線=全外連線(mysql的sql語句中也就是省略掉outer單詞)

任何乙個簡單的問題,都不是看起來那麼簡單,不知道你想過沒有,為什麼內連線要這麼叫,它**「內」了,**又「不外」了呢,我還真鑽了個牛角尖,找到兩種解釋:

、基於文氏圖的解釋

、基於資料庫對連線實現不同的解釋

基於文氏圖的解釋:

如上圖,這種解釋將待連線的兩個表,視為兩個集合,內連線結果視為兩個集合的交集,外連線視為除了內連線再加上兩表的缺失部分。

這種解釋有乙個小問題,就是中間的部分加上左邊的部分,看起來好像等於左邊表的記錄。實際上中間的記錄(內連線結果)數多於它。

基於資料庫實現的解釋

假設a_rows 為a表記錄、b_rows 為b表記錄、r_rows為結果

內連線:

select * from a inner join b where ***

資料庫偽**實現為:

for(a_row in a_rows)}}

外連線:select * from a left join b on ***

資料庫實現為:

for(a_row in a_rows)

}//外連線

if(!a_exist)

}

看上面的**,簡單模擬了兩個表的連線,內外兩層迴圈,外迴圈遍歷a表,內迴圈遍歷b表。將a、b兩表的各行組合,放入結果表中。

所以,回答上面的問題,為什麼叫內連線?是因為內連線實現時,只在內層迴圈中往結果表中插入資料,而外連線還需要在外層迴圈判斷,如結果中不存在a表的記錄,還需要額外插入一條記錄(我個人更喜歡這種解釋)。

SQL 用JOIN連線多個表

select from table1 inner join table2 on table1.id table2.id 其實 inner join on的語法格式可以概括為 from 表1 inner join 表2 on 表1.欄位號 表2.欄位號 inner join 表3 on 表1.欄位號 ...

C 深入理解虛表

虛表是記錄本類中所有虛函式位址的乙個 如下,我們設計了乙個類,存在兩個虛函式。class a virtual void fun2 通過a例項化a,再看看a的記憶體結構。vfptr就是虛表!可以把它看成存放了void 型物件的陣列。而 vfptr的兩個成員分別代表fun1函式的指標和fun2函式的指標...

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...