表的基本連接 SQL的一個重要特性就是能通過JOIN關鍵詞,從多個交叉表中查詢、分析數據。 連接表的目的 在關係資料庫中,數據表設計的一個重要原則就是要避免冗餘性。 學習本節需要的數據表: CREATE TABLE TEACHER ( ID INT IDENTITY (1,1) PRIMARY KE ...
表的基本連接
SQL的一個重要特性就是能通過JOIN關鍵詞,從多個交叉表中查詢、分析數據。
連接表的目的
在關係資料庫中,數據表設計的一個重要原則就是要避免冗餘性。
- 減少了冗餘信息,節省了資料庫存儲空間。
- 簡化了數據修改、維護操作。
學習本節需要的數據表:
CREATE TABLE TEACHER ( ID INT IDENTITY (1,1) PRIMARY KEY , --主鍵,自增長 TNO INT NOT NULL, --教工號 TNAME CHAR(10) NOT NULL, --教師姓名 CNO INT NOT NULL, --課程號 SAL INT, --工資 DNAME CHAR(10) NOT NULL, --所在系 TSEX CHAR(2) NOT NULL, --性別 AGE INT NOT NULL --年齡 ) INSERT INTO dbo.TEACHER VALUES( 1,'王軍',4,400,'數學','男',32) INSERT INTO dbo.TEACHER VALUES( 2,'李彤',5,6600,'生物','女',54) INSERT INTO dbo.TEACHER VALUES( 3,'王永軍',1,1000,'電腦','女',45) INSERT INTO dbo.TEACHER VALUES( 4,'劉曉婧',2,8000,'電腦','女',23) INSERT INTO dbo.TEACHER VALUES( 5,'高維',8,6000,'電子工程','男',54) INSERT INTO dbo.TEACHER VALUES( 6,'李偉',7,230,'機械工程','女',23) INSERT INTO dbo.TEACHER VALUES( 7,'劉輝',3,0,'生物','女',65) INSERT INTO dbo.TEACHER VALUES( 8,'劉偉',9,500,'電腦','男',23) INSERT INTO dbo.TEACHER VALUES( 9,'劉靜',12,0,'經濟管理','男',45) INSERT INTO dbo.TEACHER VALUES( 10,'劉奕鍇',13,70000,'電腦','女',65) INSERT INTO dbo.TEACHER VALUES( 11,'高維',14,70000,'經濟管理','男',61) CREATE TABLE COURSE ( ID INT IDENTITY (1,1) PRIMARY KEY , --主鍵,自增長 CNO INT NOT NULL, --課程號 CNAME CHAR(30) NOT NULL, --課程名稱 CTIME INT NOT NULL, --學時 SCOUNT INT NOT NULL, --容納人數 CTEST SMALLDATETIME NOT NULL, --考試時間 ) INSERT INTO dbo.COURSE VALUES( 4,'應用數學基礎',48,120,'2006-7-10') INSERT INTO dbo.COURSE VALUES( 5,'生物工程概論',32,80,'2006-7-8') INSERT INTO dbo.COURSE VALUES( 1,'電腦軟體基礎',32,70,'2006-7-8') INSERT INTO dbo.COURSE VALUES( 2,'電腦硬體基礎',24,80,'2006-6-28') INSERT INTO dbo.COURSE VALUES( 8,'模擬電路設計',28,90,'2006-7-10') INSERT INTO dbo.COURSE VALUES( 7,'機械設計實踐',48,68,'2006-7-14') INSERT INTO dbo.COURSE VALUES( 3,'生物化學',32,40,'2006-7-2') INSERT INTO dbo.COURSE VALUES( 9,'資料庫設計',16,80,'2006-7-1') INSERT INTO dbo.COURSE VALUES( 6,'設計理論',28,45,'2006-6-30') INSERT INTO dbo.COURSE VALUES( 10,'電腦入門',25,150,'2006-6-29') INSERT INTO dbo.COURSE VALUES( 11,'數字電路設計基礎',30,125,'2006-6-20') CREATE TABLE STUDENT ( ID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, SNO CHAR(4) NOT NULL, --學號 SNAME CHAR(10) NOT NULL, --姓名 DNAME CHAR(10) NOT NULL, --系 SSEX CHAR(2) NOT NULL, --性別 CNO INT , --課程號 MARK DECIMAL(3,1), --成績 TYPE CHAR(4) --課程類型 ) INSERT INTO dbo.STUDENT VALUES('9701','劉建國','管理工程','男',4,82.5,'必修') INSERT INTO dbo.STUDENT VALUES('9701','劉建國','管理工程','男',10,70,'選修') INSERT INTO dbo.STUDENT VALUES('9701','劉建國','管理工程','男',1,78.5,'選修') INSERT INTO dbo.STUDENT VALUES('9702','李春','環境工程','女',5,63,'必修') INSERT INTO dbo.STUDENT VALUES('9702','李春','環境工程','女',10,58,'選修') INSERT INTO dbo.STUDENT VALUES('9703','王天','生物','男',5,48.5,'必修') INSERT INTO dbo.STUDENT VALUES('9703','王天','生物','男',2,86,'選修') INSERT INTO dbo.STUDENT VALUES('9704','李華','電腦','女',4,76,'必修') INSERT INTO dbo.STUDENT VALUES('9704','李華','電腦','女',1,92,'必修') INSERT INTO dbo.STUDENT VALUES('9704','李華','電腦','女',2,89,'必修') INSERT INTO dbo.STUDENT VALUES('9704','李華','電腦','女',9,80,'必修') INSERT INTO dbo.STUDENT VALUES('9704','李華','電腦','女',8,70,'選修') INSERT INTO dbo.STUDENT VALUES('9705','孫慶','電子工程','男',8,79,'必修') INSERT INTO dbo.STUDENT VALUES('9705','孫慶','電子工程','男',1,59,'必修') INSERT INTO dbo.STUDENT VALUES('9705','孫慶','電子工程','男',11,52,'必修') INSERT INTO dbo.STUDENT VALUES('9705','孫慶','電子工程','男',6,68,'必修') INSERT INTO dbo.STUDENT VALUES('9706','高偉','機械工程','男',13,93,'必修') INSERT INTO dbo.STUDENT VALUES('9706','高偉','機械工程','男',12,88.5,'必修') INSERT INTO dbo.STUDENT VALUES('9706','高偉','機械工程','男',1,78,'選修') INSERT INTO dbo.STUDENT VALUES('9706','高偉','機械工程','男',10,76,'選修')數據表
1、簡單的二表連接
SELECT TNAME,DNAME,CNAME,CTEST FROM dbo.TEACHER,dbo.COURSE WHERE dbo.TEACHER.CNO=dbo.COURSE.CNO --查詢老師和系表的數據
根據以上SQL,可知道執行過程:
-
- 系統首先執行FROM子句,這裡FROM子句列出的有兩個表TEACHER和COURSE,DBMS將計算這兩個表的笛卡兒積,列出這兩個表中行的所有可能組合,形成一個中間表。中間表的每條記錄包含了兩個表中的所有行。
- 而後系統將執行WHERE子句,根據“dbo.TEACHER.CNO=dbo.COURSE.CNO”關係對中間表進行搜索,去除那些不滿足該條件的記錄。
- 最後系統執行SELECT語句,從執行WHERE子句後得到的中間表的每條記錄中,提取TNAME,DNAME,CNAME,CTEST這4個欄位的信息作為結果表。
註意:
由於兩張表都存在相同的欄位CNO,所以在查詢的時候要指明來自哪張表,如dbo.TEACHER.CNO、dbo.COURSE.CNO,而其他具有重名的欄位,也要進行同樣的處理,否則會報錯。
問題:
表的連接時一句關係WHERE子句來定義的,實際開發中,也一定更要用到關係連接。如果不指明連接關係呢?
SELECT TNAME,DNAME,CNAME,CTEST FROM dbo.TEACHER,dbo.COURSE
SELECT COUNT(*) AS 總條數 FROM dbo.TEACHER,dbo.COURSE --查詢一共有幾條數據
2、三表查詢(在WHERE子句中進行奪標查詢)
SELECT SNAME,dbo.STUDENT.SNAME,CNAME,CTEST,MARK,dbo.TEACHER.TNAME FROM dbo.TEACHER,dbo.COURSE,dbo.STUDENT WHERE dbo.TEACHER.CNO=dbo.COURSE.CNO AND dbo.COURSE.CNO=dbo.STUDENT.CNO
使用別名,S,T,C
SELECT SNAME,S.SNAME,CNAME,CTEST,MARK,TNAME FROM dbo.TEACHER AS T,dbo.COURSE AS C,dbo.STUDENT AS S WHERE T.CNO=C.CNO AND C.CNO=S.CNO
”dbo.TEACHER.CNO=dbo.COURSE.CNO AND dbo.COURSE.CNO=dbo.STUDENT.CNO“,含義為”只有同時存在TEACHER,STUDENT,COURSE“中CNO的信息才會作為結果顯示出來。
註意:
由於學生表和老師表都有欄位”DNAME“,在SELECT子句中查詢DNAME欄位時,我們要指定表名,否則系統會報錯。
可見,創建表的基本連接,只要遵守下麵的基本原則即可:
-
- FROM子句中應列出所有連接的表的表名。
- WHERE子句應定義連接的關聯條件。
- 當列名為多個表共有時,要指明列的所在表,即採用”表名.欄位名“的形式。
3、採用JOIN關鍵字建立連接
SELECT COLUMN
FROM join_table
JOIN_TYPE join_table
ON (join_condition)
說明如下:
-
-
- join_table指出參與連接操作的表名。
- JOIN_TYPE為連接類型,可分為四種:自然連接、內連接、外連接和交叉連接。
- 自然連接JOIN_TYPE的形式為NATURAL JOIN
- 內連接JOIN_TYPE的形式為INNER JOIN
- 外連接,又分為左連接,JOIN_TYPE形式為LEFT OUTER JOIN或LEFT JOIN;右連接,JOIN_TYPE的形式為RIGHT OUTER JOIN或RIGHT JOIN;全外連接,JOIN_TYPE的形式為CROSS JOIN;全外連接,JOIN_TYPE的形式為FULL OUTER JOIN或FULL JOIN。
- 交叉連接中JOIN_TYPE的形式為CROSS JOIN。
- ON(join_condition)子句指出連接條件,由被連接表中的列和比較遠算符、邏輯運算符等構成。
-
4、表的連接類型
4.1、自連接
SELECT DISTINCT SNO FROM dbo.STUDENT WHERE MARK<60 --查詢不及格學生學號,重覆的去除 SELECT DNAME,MARK,SNAME,CNO FROM dbo.STUDENT WHERE SNO IN('9702','9703','9705') AND MARK <60 --查詢三個學號中不及格學生的信息
4.2、內連接(INNER JOIN)
內連接也稱為等同連接,返回的結果集是兩個表中所有相匹配的數據,而捨棄不匹配的數據。查詢的結果表包含的兩源表行,必須滿足ON子句中的搜索條件。
使用等於號(=)比較被連接列的列值,在查詢結果中列出被連接表中的所有列,包括其中的重覆列。圖給出了典型的等值內連接示意圖。
SELECT s.SNAME,s.DNAME,s.CNO,t.TNAME FROM dbo.STUDENT AS s inner join dbo.TEACHER AS t ON t.CNO = s.CNO --查詢兩表部分信息
使用不等連接進行查詢 後面會講到各種運算符 先給官方網站地址:http://www.runoob.com/sqlite/sqlite-operators.html SELECT s.SNAME,s.DNAME,s.CNO,t.TNAME FROM dbo.STUDENT AS s inner join dbo.TEACHER AS t ON s.DNAME<>t.DNAME AND t.CNO = s.CNO
等價於:
SELECT s.SNAME,s.DNAME,s.CNO,t.TNAME FROM dbo.STUDENT AS s,dbo.TEACHER AS t WHERE s.DNAME<>t.DNAME AND t.CNO = s.CNO
DBMS預設多表查詢按INNER JOIN來執行,除非指定OUTER JOIN。
註意:
INNER JOIN可以實現奪標查詢,但是一次只能連接兩張表,要連接多表,必須進行多次連接。
4.2.1、使用INNER JOIN實現多表連接
--三張表進行查詢,用兩個INNER JOIN
SELECT s.SNAME,s.DNAME,c.CNAME,c.CTEST,s.MARK,t.TNAME FROM dbo.TEACHER AS t INNER JOIN dbo.COURSE AS c ON c.CNO = t.CNO INNER JOIN dbo.STUDENT AS s ON s.CNO = t.CNO
4.3、外連接(OUTER JOIN)
左外連接=內連接+左邊表中失配的元組
右外連接=內連接+右邊表中失配的元組
全外連接=內連接+左邊表中失配的元組+右邊表中失配的元組
表達式示意圖如:
SELECT s.SNO,s.SNAME,c.CNO,c.CNAME,c.CTEST,s.MARK FROM dbo.STUDENT AS s LEFT OUTER JOIN dbo.COURSE AS c ON c.CNO = s.CNO
在WHERE子句中用”*=“實現左外連接
SELECT s.SNO,s.SNAME,c.CNO,c.CNAME,c.CTEST,s.MARK FROM dbo.STUDENT AS s,dbo.COURSE AS c WHERE c.CNO *= s.CNO
----三種連接方式都一樣,只需要改”LEFT OUTER JOIN“為”RIGHT OUTER JOIN“和”FULL OUTER JOIN“,
就不做三個演示了,可以自己對比數據的異同
4.4、交叉連接(CROSS JOIN)
除了在FROM子句中使用逗號間隔連接的表外,SQL還支持另一種被稱為交叉連接的操作,它們都返回被連接的兩個表所有數據行的笛卡爾積,返回到的數據行數等於第一個表中符合查詢條件的數據行數乘以第二個表中符合查詢條件的數據行數。惟一的不同在於,交叉連接分開列名時,使用CROSS JOIN關鍵字而不是逗號。
實際上,下麵兩個表達式是等價的。
SELECT * FROM table1, table2 SELECT * FROM table1 CROSS JOIN table2
交叉連接示意圖:
SELECT s.SNO,s.SNAME,c.CNO,s.CNO,c.CNAME,c.CTEST,s.MARK FROM dbo.STUDENT AS s CROSS JOIN dbo.COURSE AS c WHERE s.CNO=c.CNO AND s.MARK>60
註意:
在使用CROSS JOIN關鍵字交叉連接表時,因為生成的是兩個表的笛卡爾積,因而不能使用ON關鍵字,只能在WHERE子句中定義搜索條件。
事實上,直接使用CROSS JOIN很少得到想要的結果,但是,正如實例所示,作為查詢的第一步,DBMS通常在FROM子句中,對連接的表進行CROSS JOIN,然後過濾得到的中間表。