1. 程式人生 > 實用技巧 >SQL 多表查詢之 where和INNER JOIN

SQL 多表查詢之 where和INNER JOIN

SQL多表查詢之 where和INNER JOIN【基礎查詢和效率分析】

轉載最後釋出於2018-07-05 10:40:47閱讀數 18057收藏

https://blog.csdn.net/u013372487/article/details/52622491?locationNum=1

https://blog.csdn.net/qingtanlang/article/details/2133816

http://www.cnblogs.com/drake-guo/p/6101531.html

https://blog.csdn.net/huyr_123/article/details/61616547

在多表查詢中,一些SQL開發人員更喜歡使用WHERE來做join,比如:

SELECT a.ID, b.Name, b.Date FROM Customers a, Sales b WHERE a.ID = b.ID;

缺點:在上面語句中,實際上是建立了兩張表的笛卡爾積,所有可能的組合都會被創建出來。在笛卡爾連線中,在上面的例子中,如果有1000顧客和1000條銷售記錄,這個查詢會先產生1000000個結果,然後通過正確的 ID過濾出1000條記錄。 這是一種低效利用資料庫資源,資料庫多做100倍的工作。 在大型資料庫中,笛卡爾連線是一個大問題,對兩個大表的笛卡爾積會建立數10億或萬億的記錄。

為了避免建立笛卡爾積,應該使用INNER JOIN :

SELECT a.ID, b.Name, b.Date FROM Customers a INNER JOIN Sales b ON a.ID = b.ID;

優點:如上面語句,使用inner join 這樣資料庫就只產生等於ID 的1000條目標結果。增加了查詢效率。

有些資料庫系統會識別出 WHERE連線並自動轉換為 INNER JOIN。在這些資料庫系統中,WHERE 連線與INNER JOIN 就沒有效能差異。但是, INNER JOIN 是所有資料庫都能識別的,因此DBA會建議在你的環境中使用它。

  1. INNERJOIN(內連線,或等值連線):獲取兩個表中欄位匹配關係的記錄。
  2. LEFTJOIN(左連線):獲取左表所有記錄,即使右表沒有對應匹配的記錄。
  3. RIGHTJOIN(右連線): 與LEFTJOIN 相反,用於獲取右表所有記錄,即使左表沒有對應匹配的記錄。

注意:
1、INNER JOIN 等同於 JOIN;
2、示意圖:

我在練習MySQL操作語句時,使用一條完全沒有錯誤的語句:

update students set name='drake' where name='chuan';

卻報瞭如下錯誤:

Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences -> SQL Queries and reconnect.
簡單翻譯一下:
你正在使用 安全更新模式(safe upate mode)並且你在嘗試 update 一個表時 沒有用帶有鍵的列 作為where條件,在首選項中切換選項。

初學者在修改一個值時可能會用以下語句:

update t set col='new_value' 

而這正是很多人常犯的錯誤。因為他沒有限定條件,會將表中所有的記錄都修改一遍。

為了防止這種錯誤出現,我們可以開啟安全更新模式(safe update mode):

set [global] SQL_SAFE_UPDATES = 1;

在update操作中:當where條件中列(column)沒有索引可用且無limit限制時會拒絕更新。where條件為常量且無limit限制時會拒絕更新。

在delete操作中:當①where條件為常量,②或where條件為空,③或where條件中 列(column)沒有索引可用且無limit限制時拒絕刪除。

需要注意的是:

update操作中,where可以為常量 ,where條件中列(column)可以沒有索引。但是需要有limit限制。

然而delete要嚴格一些:where不能為常量,且where條件中列(column)不能沒有索引!

1 .WHERE子句中使用的連線語句,在資料庫語言中,被稱為隱性連線。INNER JOIN……ON子句產生的連線稱為顯性連線。(其他JOIN引數也是顯性連線)WHERE 和INNER JOIN產生的連線關係,沒有本質區別,結果也一樣。但是!隱性連線隨著資料庫語言的規範和發展,已經逐漸被淘汰,比較新的資料庫語言基本上已經拋棄了隱性連線,全部採用顯性連線了。

2 .無論怎麼連線,都可以用join子句,但是連線同一個表的時候,注意要定義別名,否則產生錯誤!

a> left join:理解為“有效連線”,兩張表中都有的資料才會顯示left join:理解為“有左顯示”,比如on a.field=b.field,則顯示a表中存在的全部資料及a//b中都有的資料,A中有、B沒有的資料以null顯示

b> right join:理解為“有右顯示”,比如on a.field=b.field,則顯示B表中存在的全部資料及a//b中都有的資料,B中有、A沒有的資料以null顯示

c> full join:理解為“全連線”,兩張表中所有資料都顯示,實際就是inner +(left-inner)+(right-inner)

3 .join可以分主次表 外聯接有三種類型:完全外聯,左聯,右聯.
完全外聯包含兩張表的所有記錄.
左聯是以左邊的表為主,右邊的為輔,右聯則相反

語法格式:
其實 INNER JOIN ……ON的語法格式可以概括為:
FROM (((表1 INNER JOIN 表2 ON 表1.欄位號=表2.欄位號) INNER JOIN 表3 ON 表1.欄位號=表3.欄位號) INNER JOIN 表4 ON Member.欄位號=表4.欄位號) INNER JOIN 表X ON Member.欄位號=表X.欄位號
您只要套用該格式就可以了。

現成格式範例:
雖然我說得已經比較明白了,但為照顧初學者,我還是以本會員註冊系統為例,提供一些現成的語法格式範例,大家只要修改其中的資料表名稱和欄位名稱即可。

連線兩個資料表的用法:
FROM Member INNER JOIN MemberSort ON Member.MemberSort=MemberSort.MemberSort
語法格式可以概括為:
FROM 表1 INNER JOIN 表2 ON 表1.欄位號=表2.欄位號

連線三個資料表的用法:
FROM (Member INNER JOIN MemberSort ON Member.MemberSort=MemberSort.MemberSort) INNER JOIN MemberLevel ON Member.MemberLevel=MemberLevel.MemberLevel
語法格式可以概括為:
FROM (表1 INNER JOIN 表2 ON 表1.欄位號=表2.欄位號) INNER JOIN 表3 ON 表1.欄位號=表3.欄位號

連線四個資料表的用法:
FROM ((Member INNER JOIN MemberSort ON Member.MemberSort=MemberSort.MemberSort) INNER JOIN MemberLevel ON Member.MemberLevel=MemberLevel.MemberLevel) INNER JOIN MemberIdentity ON Member.MemberIdentity=MemberIdentity.MemberIdentity
語法格式可以概括為:
FROM ((表1 INNER JOIN 表2 ON 表1.欄位號=表2.欄位號) INNER JOIN 表3 ON 表1.欄位號=表3.欄位號) INNER JOIN 表4 ON Member.欄位號=表4.欄位號

連線五個資料表的用法:
FROM (((Member INNER JOIN MemberSort ON Member.MemberSort=MemberSort.MemberSort) INNER JOIN MemberLevel ON Member.MemberLevel=MemberLevel.MemberLevel) INNER JOIN MemberIdentity ON Member.MemberIdentity=MemberIdentity.MemberIdentity) INNER JOIN Wedlock ON Member.Wedlock=Wedlock.Wedlock
語法格式可以概括為:
FROM (((表1 INNER JOIN 表2 ON 表1.欄位號=表2.欄位號) INNER JOIN 表3 ON 表1.欄位號=表3.欄位號) INNER JOIN 表4 ON Member.欄位號=表4.欄位號) INNER JOIN 表5 ON Member.欄位號=表5.欄位號

sql(join on 和where的執行順序)

left join :左連線,返回左表中所有的記錄以及右表中連線欄位相等的記錄。

right join :右連線,返回右表中所有的記錄以及左表中連線欄位相等的記錄。

inner join: 內連線,又叫等值連線,只返回兩個表中連線欄位相等的行。

full join:外連線,返回兩個表中的行:left join + right join。

cross join:結果是笛卡爾積,就是第一個表的行數乘以第二個表的行數。

關鍵字:on

資料庫在通過連線兩張或多張表來返回記錄時,都會生成一張中間的臨時表,然後再將這張臨時表返回給使用者。

在使用leftjion時,on和where條件的區別如下:

1、on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。

2、where條件是在臨時表生成好後,再對臨時表進行過濾的條件。這時已經沒有leftjoin的含義(必須返回左邊表的記錄)了,條件不為真的就全部過濾掉。

假設有兩張表:

表1:tab2

id size
1 10
2 20
3 30

表2:tab2

size name
10 AAA
20 BBB
20 CCC

兩條SQL:
1、select*formtab1leftjointab2on(tab1.size=tab2.size)wheretab2.name=’AAA’
2、select*formtab1leftjointab2on(tab1.size=tab2.sizeandtab2.name=’AAA’)

第一條SQL的過程:

1、中間表
on條件:
tab1.size=tab2.size
tab1.id tab1.size tab2.size tab2.name
1 10 10 AAA
2 20 20 BBB
2 20 20 CCC
3 30 (null) (null)

2、再對中間表過濾
where條件:
tab2.name=’AAA’
tab1.id tab1.size tab2.size tab2.name
1 10 10 AAA

第二條SQL的過程:

1、中間表
on條件:
tab1.size=tab2.sizeandtab2.name=’AAA’
(條件不為真也會返回左表中的記錄)
tab1.id tab1.size tab2.size tab2.name
1 10 10 AAA
2 20 (null) (null)
3 30 (null) (null)

其實以上結果的關鍵原因就是leftjoin,rightjoin,fulljoin的特殊性,不管on上的條件是否為真都會返回left或right表中的記錄,full則具有left和right的特性的並集。而innerjion沒這個特殊性,則條件放在on中和where中,返回的結果集是相同的。

連線查詢是將兩個或多個的表按某個條件連線起來,從中選取需要的資料,連線查詢是同時查詢兩個或兩個以上的表的使用的。當不同的表中存在相同意義的欄位時,可以通過該欄位來連線這幾個表。

1.內連線查詢

內連線查詢是一種最常用的連線查詢。內查詢可以查詢兩個或兩個以上的表。舉例說明兩個表的連線查詢。當該欄位的值相等時,就查詢出該記錄。

舉個栗子~

SELECT num,name,employee.d_id,sex,d_name,function

FROM employee ,department

WHERE employee.d_id=department.d_id;

2.外連線查詢

基本語法:

SELECT 屬性名列表

FROM 表名1 LEFT | RIGHT JOIN 表名2

ON 表名1.屬性1=表名2.屬性2;

  • 左連線查詢

進行左連線查詢時,可以查出表1的表中所有記錄,而表2所指的表中,只能查詢出匹配的記錄

  • 右連線查詢

進行右連線查詢時,可以查出表2的表中所有記錄,而表1所指的表中,只能查詢出匹配的記錄

3.複合·條件查詢

在連線查詢時,也可以增加其他的限制條件,使查詢結果更加準確。

子查詢

子查詢是將一個查詢語句巢狀在另外一個查詢語句中,內層查詢語句的查詢結果,可以為外層查詢語句提供查詢條件。

舉個栗子~IN

SELECT * FROM employee

WHERE d_id IN

(SELECT d_id FROM department);

還舉個栗子~比較運算子

SELECT id ,name, score FROM computer_stu

WHERE score>=

(SELECT score FROM scholarship

WHERE level=1);

還舉個栗子~EXISTS(表示存在,使用EXISTS關鍵字時,內層查詢語句不反悔查詢的記錄,而是返回一個真假值)

SELECT * FROM employee

WHERE EXISTS

( SELECT d_name FROM department

WHERE d_id =1003);

還舉個栗子~ANY(表示滿足其中任一條件)

如查詢獲得任意一個獎學金的最低分,即只要獲得獎學金都滿足條件

SELECT * FROM computer_stu

WHERE score >=ANY

( SELECT score FROM scholarship);

最後一個栗子~ALL(表示滿足所有條件)

如查詢獲得最高獎學金的記錄

SELECT * FROM computer_stu

WHERE score >=ALL

( SELECT score FROM scholarship);