mysql join

MySQL使用JOIN來連接多個表查詢數據,主要使用的JOIN算法只有一種,那就是nested-loop join。

nested-loop join算法實現的機制很簡單,就是從驅動表中選取數據作爲循環基礎數據,然後以這些數據作爲查詢條件到下一個表中進行查詢,如此往復。這個實現機制類似於foreach函數的遍歷。因此帶來的問題就是連接的表越多,函數嵌套的層數就越多,算法複雜度呈指數級增長。

因此,設計查詢要儘量減少連接的表的個數。

驅動表是指:在使用多表嵌套連接時,首先,全表掃描該驅動表,然後用驅動表返回的結果集逐行去匹配被驅動的表(可以利用索引),數據庫基於成本可能會選擇小表作爲驅動表,而被驅動表使用索引進行連接。

JOIN語句的含義是把兩張(或者多張)表的屬性通過它們的值組合在一起,一般會遇到如下3種連接。

·等值連接([INNER]JOIN)

·左外連接(LEFT JOIN)

·右外連接(RIGHT JOIN)

示例用表見圖3-4~圖3-6所示。

圖3-4 職員表

在部門職員表中,如果是在職員工,那麼to_date的值爲'9999-01-01'。

圖3-5 部門表

圖3-6 部門職員表

(1)內連接

內連接(INNER JOIN)是應用程序中普遍應用的“連接”操作,它一般都是默認的連接類型。內連接基於連接謂詞將兩張表(如A和B)的列組合在一起,從而產生新的結果表。

內連接可以被進一步分爲等值連接、自然連接和交叉連接。較常用的是等值連接。

以下是等值連接的示例。

查詢目前在職的所有員工的姓名及其所在的部門時可使用如下語句。

輸出結果如圖3-7所示。

自然連接(natural join)是等值連接的進一步特例化。兩表做自然連接時,兩表中名稱相同的所有列都將被比較,這是隱式的。自然連接得到的結果表中,兩表中名稱相同的列只出現一次。一般應該避免使用自然連接,因爲我們無法指定連接列,且

這種寫法隱藏了我們的JOIN關係,如果以後數據模型發生了變化,可能會導致出現非預期的結果。

交叉連接(笛卡兒積) 把表視爲行記錄的集合,交叉連接即返回這兩個集合的笛卡兒積。這其實等價於內連接的連接條件爲“永真”,或者連接條件不存在的情況。

示例如下。

圖3-7 在職員工的姓名和部門的等值連接

SELECT * FROM a JOIN b;

SELECT * FROM a,b;

SQL定義了兩種不同的語法方式來表示“連接”。一種是“顯式連接符號”,顯式地使用關鍵字JOIN,另一種是“隱式連接符號”,它使用所謂的“隱式連接符號”。隱式連接符號把需要連接的表放到SELECT語句的FROM部分,並用逗號隔開。這樣就構成了一個“交叉連接”,WHERE語句可能會放置一些過濾謂詞(過濾條件)。那些過濾謂詞在功能上等價於顯式連接符號。

如上所述的例子中,查詢目前在職的所有員工的姓名及所在部門時,可以寫成如下的形式。

它等價於:

ON表達式是任何可以用於WHERE子句的條件表達式,一般來說,你應該只在ON表達式裏指定如何JOIN表,而把篩選結果集的條件放到WHERE子句中。

(2)外連接(OUT JOIN)

並未要求連接的兩表的每一條記錄在對方的表中都必須有一條匹配的記錄。連接表保留所有的記錄,甚至這條記錄沒有匹配的記錄也要保留。外連接可依據連接表保留左表、右表或全部表的行而進一步分爲左外連接、右外連接和全外連接。全外連接一般沒有什麼意義,MySQL並不直接支持全外連接,但可以通過左右外連接的並集(UNION)來模擬實現。

1)左外連接(LEFT JOIN、LEFT OUTER JOIN)

左外連接也簡稱爲左連接(LEFT JOIN),若A和B兩表進行左外連接,那麼結果表中將包含“左表”(即表A)的所有記錄,即使那些記錄在“右表”B中沒有符合連接條件的匹配。這就意味着即使ON語句在表B中的匹配項是0條,連接操作也還是會返回一條記錄,只不過這條記錄中的來自於表B的每一列的值都爲NULL。

之前的示例曾演示過插入一些記錄(員工號111111、111112、111113、111114)到employees表中,但還沒有指定新插入員工記錄的部門。現在用如下語句聯合查詢下僱員表和部門–僱員表。

結果如圖3-8所示,可以看到有些員工沒有部門,dept_no(部門代碼)顯示爲NULL。

2)右外連接(RIGHT JOIN、RIGHT OUT JOIN)

右外連接也簡稱右連接(RIGHT JOIN),它與左外連接完全類似,只不過是連接表的順序相反而已。如果A表右連接B表,那麼“右表”B中的每一行在連接表中至少會出現一次。如果B表的記錄在“左表”A中未找到匹配行,則連接表中來源於A表中的列的值將設爲NULL,示例如下。

實際上,顯式的右外連接很少使用,因爲它的可讀性不佳,所以總是被改寫成左連接。

圖3-8 查詢一些員工的部門

如果JOIN的層次比較多,則需要留意一下可讀性,如果不能確定優先級,那麼建議使用括號來明確優先級,以避免犯錯誤。例如,在以下的例子中,由於逗號的優先級比JOIN表達式低,因此可能會導致我們犯錯誤。

上述代碼實際上是:

但這其實並不是我們的本意,應該寫成如下的形式(用括號來提升優先級別)。

使用JOIN命令操作表的時候,需要留意如果表按條件篩選的記錄是不確定的,可能就會導致非預期的結果。下面以圖3-9和圖3-10所示的數據爲例來進行說明。

圖3-9 t1表

圖3-10 t2表

對於如下的查詢:

由於code='b'在兩個表中都可以唯一確定一條記錄,因此查詢會返回合理的結果(如圖3-11所示)。

圖3-11 返回正確的結果

而對於如下查詢:

由於t2表code='a'會返回多個值。最終的查詢結果返回了3條記錄(如圖3-12所示),因此可能不是我們所需要的結果。

圖3-12 返回錯誤的結果

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章