SQL之“多表查詢”
前幾篇中我們查詢的資料都是在一張表中進行操作的,但是實際工作中我們期望的資料往往分散在不同的表中,這時就需要下面我將寫到的內容:從多張表中去獲取資料。
一、表的加法
表的加法用英文單詞表示:union,是將兩張表的資料按行合併在一起。表的加法會把兩個表中重複的資料刪除只保留一個。如果想要保留兩個表中重複的行,用union all 查詢語句。
練習:
二、表的聯接
關係資料庫裡各個表之間如何建立起關係呢?
下圖是4張表聯接關係圖,我們可以從中看出這4張表中的聯接關係
表和表之間是透過列直接產生對應關係的,聯接是透過表和表之間的關係將兩個表合併在一起的操作,聯接的型別有:
交叉聯接(cross join)
如圖,cross join是將一個表中的每一行都與另一張表中的每一行合併在一起。交叉聯接在實際業務中用得較少,因為結果數行太多了,需要花費大量裝置的支援且沒有什麼實際價值。但
它是其他聯接的基礎。
#FormatImgID_7##FormatImgID_8#
練習:
內聯接(inner join)
查找出同時存在於兩張表中的資料。下圖是內聯接的聯接過程:
我們看下內聯接的SQL查詢語句,有三個關鍵地方
from子句中由原來的只有一張表變為兩張表,且用as關鍵字對兩張表起了別名方便我們使用。select子句中所選列都加了表的別名,表名是從特定表取出的列。
from 子句中用inner join 將兩張表聯接起來。表明聯接方式是內聯接,選取出同時存在於兩張表中的資料。
from 子句中的關鍵字on 後表示兩個表是透過哪個列匹配產生關係。
練習:
左聯接(left join)
左聯接會把左側表中的資料全部取出來。我們看下左聯接在這兩個表上是如何和執行的:
左聯接會將左側的表作為主表並全部取出,右邊的表中只選出和左邊表相同學號的行並進行合併。如果左側表某行在右側沒有對應學號,相應列則為空值。
左聯接的SQL查詢語句只是將上述內聯接語句中的inner join變為left join,其他不變。
再看一個問題,圖片中紅色區域如何表示呢?
#FormatImgID_21##FormatImgID_22#
它是在左聯接的基礎上去掉了兩個表共同的地方。在原來的SQL語句中加入
“where b。學號 is null”表示右邊表的學號為空值,這樣就選出來左邊表去掉公共部分的資料。
練習:
透過上圖區別,我想提一下在這裡要注意一個問題:
NULL表示不可知不確定,NULL不與任何值相等(包括其本身)
IS NULL 判斷某個字元是否為空,並不代表空字元或者是0;
=NULL 是判斷某個值是否等於NULL。
總之,要判斷一個數是否等於NULL只能用 IS NULL 或者 IS NOT NULL 來判斷
右聯接(right join)
右聯接會將右側表中的資料全部取出來。
練習:
同樣在右聯接的基礎上再看一個問題,紅色區域部分怎麼表示呢,和左聯接部分同理。
全聯接(full join)
全聯接的查詢結果會返回左右表中的所有行,當左右表的行有匹配時兩個表會進行合併,若某一行與另一個表沒有匹配時,另一個表對應的值用空值來填充。這樣兩個表中的資料就都在聯接結果中了。
MySQL是不支援全聯接的,這裡理解下全聯接概念即可。
總結:什麼時候用哪一種聯接呢?
當實際工作業務中,要生成固定行數的表單或特別說明了哪一張表裡的全部資料時會使用左聯接或右聯接,其他情況都用內聯接來獲取兩個表的公共部分。
兩個表進行聯接時在from 子句中加入聯接語句,並不會影響SQL查詢語句的執行順序:
三、 聯接應用案例
案例一:
查詢所有學生的學號、姓名、選課數、總成績
案例二:查詢平均成績大於85的所有學生的學號、姓名和平均成績
案例三:查詢學生的選課情況:學號、姓名、課程號、課程名稱
四、Case 表示式
使用case表示式可以幫助我們解決複雜的查詢問題,它的作用相當於進行一個條件判斷的函式,用來判斷每一行是不是滿足某個條件。
下圖是case表示式的SQL語句,裡面的when子句用來判斷某行資料是否符合某個條件,如果符合條件就執行後面的then子句,case表示式也就此結束;如果不符合條件就進行下一個when子句。
如下圖,要判斷成績及格或不及格就可以在select子句中用case表示式(
注意:中間無逗號
),並且給這列起了一個別名“是否幾個”,會將查詢結果放入裡面。
對照下圖可以看下此語句是怎樣執行的:
接著再看下兩個案例:
案例一
:查詢出每門課程的及格人數和不及格人數:
注意事項:
else子句可以省略不寫,這時會預設為else 為空值,但不建議省略。
end不能省略不寫。
case表示式可以寫到SQL語句的任意子句中。
案列二
:
使用分段[100-85],[85-70],[70-60],[<60]來統計各科成績,分別統計各分數段人數:課程ID和課程名稱。
(這種涉及到自定義的分組,妥妥的用case表示式)
這裡要用課程號與課程名稱兩個列來分組,理由是:group by本來只用課程號就可以了,但是查詢結果要我們顯示出課程名稱,我們學習group by 子句時select 裡的列名只能是group by子句裡的列名。為了讓查詢結果同時顯示出課程名稱,故group by 子句里加入了課程名稱。這裡加入的前提是不影響分組結果,如果影響分組的話就不能加了。
五.sqlzoo題目練習