MySQL數據庫與JDBC編程(二)

多表連接查詢

多表連接查詢有兩種規範,較早的SQL 92規範支持如下幾種多表連接查詢。

  • 等值連接
  • 非等值連接
  • 外連接
  • 廣義笛卡爾積

SQL 99範圍提供了可讀性更好的多表連接語法,並提供了更多類型的連接查詢。SQL 99支持如下幾種多表連接查詢

  • 交叉連接
  • 自然連接
  • 使用using子句的連接
  • 使用on子句的連接
  • 全外連接或者左、右連接

SQL 92的連接查詢

SQL 92的多表連接語法比較簡潔,這種語法把多個數據表都放在from之後,多個表之間以逗號隔開;連接條件放在where之後,與查詢條件之間用and邏輯運算符連接。如果連接條件要求兩列值相等,則稱爲等值連接,否則稱爲非等值連接;如果沒有任何連接條件,則稱爲廣義笛卡爾積。SQL 92中多表連接查詢的語法格式如下:

select column1,column2 ...
from table1, table2 ...
[where join_condition]

如下SQL語句查詢出所有學生的資料以及對應的老師姓名

select s.*, teacher_name 
# 指定多個數據表,並指定表別名
from student_table s, teacher_table t
# 使用where指定連接條件
where
s.java_teacher=t.teacher_id;

實際上,多表查詢的過程可理解爲一個嵌套循環,這個嵌套循環的僞碼如下

// 依次遍歷teacher_table 表中的每條記錄
for t in teacher_table
{
	// 遍歷student_table表中的每條記錄
	for s in student_table
	{
		// 當滿足連接條件時,輸出兩個表連接後的結果
		if(s.java_teacher=t.teacher_id)
			output s + t
	}
}

理解了上面的僞碼後,我們就可以很輕易地理解多表連接查詢的運行機制。如果求廣義笛卡爾積,則where子句後沒有任何連接條件,相當於沒有上面的if語句,廣義笛卡爾積的結果會有n x m 條記錄。只要把where後的連接條件去掉,就可以得到廣義笛卡爾積

# 不使用連接條件,得到廣義笛卡爾積
select s.*, teacher_name
# 指定多個數據表,並指定表別名
from student_table s , teacher_table t;

如果還需要對記錄進行過濾,則將過濾條件和連接條件使用and連接起來

select s.*, teacher_name
# 指定多個數據表,並指定表別名
from student_table s, teacher_table t
# 使用where指定連接條件,並指定student_name列不能爲null
where s.java_teacher=t.teacher_id and s.student_name is not null;

自連接只是連接的一種用法,並不是一種連接類型,不管是SQL 92還是SQL 99都可以使用自連接查詢。自連接的本質就是把一個表當成兩個表來用

SQL 99的連接查詢

SQL 99的連接查詢與SQL 92的連接查詢原理基本相似,不同的是SQL 99連接查詢的可讀性更強,查詢用的多個數據表顯式使用xxx join 連接,而不是直接依次排列在from之後,from後只需要放一個數據表;連接條件不再放在where之後,而是提供了專門的連接條件子句。

交叉連接(cross join)

交叉連接效果就是SQL 92中的廣義笛卡爾積,所以交叉連接無須任何連接條件

select s.*, teacher_name
# SQL 99多表連接查詢的from後只有一個表名
from student_table s
# cross join 交叉連接,相當於廣義笛卡爾積
cross join teacher_table t;
自然連接(natural join)

自然連接表面上看起來也無須指定連接條件,但自然連接是有連接條件的,自然連接會以兩個表中的同名列作爲連接條件;如果兩個表中沒有同名列,則自然連接與交叉連接效果完全一樣,因爲沒有連接條件。

select s.*, teacher_name
# SQL 99多表連接查詢的from後只有一個表名
from student_table s
# natural join 自然連接使用兩個表中的同名列作爲連接條件
natural join teacher_table t;
using 子句連接

using子句可以指定一列或多列,用於顯式指定兩個表中的同名列作爲連接條件。假設兩個表中有超過一列的同名列,如果使用natural join,則會把所有的同名列當成連接條件;使用using子句,就可顯式指定使用哪些同名列作爲連接條件

select s.*, teacher_name
# SQL 99多表連接查詢的from後只有一個表名
from student_table s 
# join連接另一個表
join teacher_table t
using(teacher_id);
on子句連接

這是最常用的連接方式,SQL 99語法的連接條件放在on子句中指定,而且每個on子句只指定一個連接條件。這意味着:如果需要進行N表連接,則需要有N-1個join…on對

select s.*, teacher_name
from student_table s
join teacher_table t
# 使用on來指定連接條件
on s.java_teacher = t.teacher_id;

使用on子句的連接完全可以代替SQL 92中的等值連接、非等值連接,因爲on子句的連接條件除了等值條件之外,也可以是非等值條件

select s.*, teacher_name
from student_table s
join teacher_table t
# 使用on來指定連接條件:非等值連接
on s.java_teacher > t.teacher_id;
左、右、全外連接

這3種外連接分別使用left [outer] join、right [outer] join和full [outer] join,這3種外連接的連接條件一樣通過on子句來指定,既可以是等值連接條件,也可以是非等值連接條件

下面使用右外連接,連接條件是非等值連接

select s.*, teacher_name
from student_table s
right join teacher_table t
# 使用on來指定連接條件:非等值連接
on s.java_teacher < t.teacher_id;

下面使用左外連接,連接條件是非等值連接

select s.*, teacher_name
from student_table s
# left join 左外連接另一個表
left join teacher_table t
# 使用on來指定連接條件:非等值連接
on s.java_teacher > t.teacher_id;

SQL 99左外連接將會把左邊表中所有不滿足連接條件的記錄全部列出;SQL 99右外連接將會把右邊表中所有不滿足連接條件的記錄全部列出。

SQL 99的全外連接會把兩個表中所有不滿足連接條件的記錄全部列出,但MySQL不支持全外連接

子查詢

子查詢就是指在查詢語句中嵌套另一個查詢,子查詢可以支持多層嵌套。對於一個普通的查詢語句而言,子查詢可以出現在兩個位置、

  1. 出現在from語句後當成數據表,這種用法也被稱爲行內視圖,因爲該子查詢的實質就是一個臨時視圖。
  2. 出現在where條件後作爲過濾條件的值。

下面的SQL語句示範了把子查詢當成數據表的用法

select *
# 把子查詢當成數據表
from (select * from student_table) t
where t.java_teacher > 1;

把子查詢當成數據表的用法更準確地說是當成視圖,我們可以把上面的SQL語句理解成在執行查詢時創建了一個臨時視圖,該視圖名爲t,所以這種臨時創建的視圖也被稱爲行內視圖。理解了這種子查詢的實質後,不難知道這種子查詢可以完全代替查詢語句中的數據表,包括在多表連接查詢中使用這種子查詢。

還有一種情況,我們可以把子查詢當成where條件中的值,如果子查詢返回單行、單列值,則被當成一個標量值使用,也就可以使用單行記錄比較運算符。

select * 
from student_table
where java_teacher >
# 返回單行、單列的子查詢可以當成標量值使用
(select teacher_id from teacher_table where teacher_name='zhangsan');

如果子查詢返回多個值,則需要使用 in 、any和all等關鍵字,in可以單獨使用,此時可以把子查詢返回的多個值當成一個值列表

select * 
from student_table
where student_id in 
(select teacher_id from teacher_table);

any和all可以與>、>=、<、<=、<>、=等運算符結合使用,與any結合使用分別表示大於、大於等於、小於、小於等於、不等於、等於其中任意一個值;與all結合使用分別表示大於、大於等於、小於、小於等於、不等於、等於全部值。從上面介紹中可以看出,=any的作用與in的作用相同。

select * 
from student_table
where student_id=
any(select teacher_id from teacher_table);

<any只要小於值列表中的最大值即可,>any只要大於值列表中的最小值即可。<all要求小於值列表中的最小值,>all要求大於值列表中的最大值

還有一種子查詢可以返回多行、多列,此時where子句中應該有對應的數據列,並使用圓括號將多個數據列組合起來。

select * 
from student_table
where (student_id,student_name)
=any(select teacher_id,teacher_name from teacher_table);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章