連表查詢
連接查詢包括合并、內(nèi)連接、外連接和交叉連接,如果涉及多表查詢,了解這些連接的特點(diǎn)很重要。
只有真正了解它們之間的區(qū)別,才能正確使用。
1、Union
UNION 操作符用于合并兩個(gè)或多個(gè) SELECT 語句的結(jié)果集。
UNION 運(yùn)算符通過組合其他兩個(gè)結(jié)果表(例如 TABLE1 和 TABLE2)并消去表中任何重復(fù)行而派生出一個(gè)結(jié)果表。
當(dāng) ALL 隨 UNION 一起使用時(shí)(即 UNION ALL),不消除重復(fù)行。兩種情況下,派生表的每一行不是來自 TABLE1 就是來自 TABLE2。
注意:使用UNION時(shí),兩張表查詢的結(jié)果有相同數(shù)量的列、列類型相似。

1)基本UNION查詢,查詢學(xué)校教師、學(xué)生的總的信息表,包括ID和姓名
SELECT ID,Name FROM Students
UNION
SELECT ID,Name FROM Teachers
2)帶條件的UNION查詢,也可以查詢同一張表,查詢年齡為18,23歲的學(xué)生信息
SELECT ID,Name FROM Student WHERE Age=18
UNION
SELECT ID,Name FROM Student WHERE Age=23
當(dāng)然,這可以使用IN或者OR很容易實(shí)現(xiàn),這里只是點(diǎn)到,以后遇到復(fù)雜查詢,相信你會用到。
3)查詢教師學(xué)生全部姓名
因?yàn)閁NION只會選擇不同的值,如果學(xué)生中和教師中有重名的情況,這就需要UNION ALL
SELECT Name FROM Students
UNION ALL
SELECT Name FROM Teachers
2、INNER JOIN(內(nèi)連接)
INNER JOIN(內(nèi)連接),也成為自然連接
作用:根據(jù)兩個(gè)或多個(gè)表中的列之間的關(guān)系,從這些表中查詢數(shù)據(jù)。
注意: 內(nèi)連接是從結(jié)果中刪除其他被連接表中沒有匹配行的所有行,所以內(nèi)連接可能會丟失信息。
重點(diǎn):內(nèi)連接,只查匹配行。
語法:(INNER可省略)
SELECT fieldlist FROM table1 [INNER] join table2 ON table1.column=table2.column

實(shí)例:查詢學(xué)生信息,包括ID,姓名、專業(yè)名稱
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students INNER JOIN MajorsON Students.MajorID = Majors.ID
結(jié)果:

根據(jù)結(jié)果可以清晰看到,確實(shí)只有匹配的行。學(xué)生Lucy的信息丟失了。
但是,inner join也會產(chǎn)生重復(fù)數(shù)據(jù)。如果將Majors表的主鍵約束去掉,可以插入重復(fù)的ID,如:
DELETE FROM Majors
INSERT INTO Majors(ID,Name) VALUES(10,'English')
INSERT INTO Majors(ID,Name) VALUES(10,'Computer')
繼續(xù)執(zhí)行上面的關(guān)聯(lián)語句,結(jié)果為:

RIGHT JOIN 結(jié)果與INNER JOIN一樣。
后續(xù)我們會深入研究JOIN的具體原理。
3、外連接
與內(nèi)連接相比,即使沒有匹配行,也會返回一個(gè)表的全集。
外連接分為三種:左外連接,右外連接,全外連接。對應(yīng)SQL:LEFT/RIGHT/FULL OUTER JOIN。通常我們省略outer 這個(gè)關(guān)鍵字。寫成:LEFT/RIGHT/FULL JOIN。
重點(diǎn):至少有一方保留全集,沒有匹配行用NULL代替。
1)LEFT OUTER JOIN,簡稱LEFT JOIN,左外連接(左連接)
結(jié)果集保留左表的所有行,但只包含第二個(gè)表與第一表匹配的行。第二個(gè)表相應(yīng)的空行被放入NULL值。
依然沿用內(nèi)鏈接的例子
(1)使用左連接查詢學(xué)生的信息,其中包括學(xué)生ID,學(xué)生姓名和專業(yè)名稱。
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students LEFT JOIN MajorsON Students.MajorID = Majors.ID

** 結(jié)論:**
通過結(jié)果,我們可以看到左連接包含了第一張表的所有信息,在第二張表中如果沒有匹配項(xiàng),則用NULL代替。
2)RIGHT JOIN(right outer join)右外連接(右連接)
右外連接保留了第二個(gè)表的所有行,但只包含第一個(gè)表與第二個(gè)表匹配的行。第一個(gè)表相應(yīng)空行被入NULL值。
右連接與左連接思想類似。只是第二張保留全集,如果第一張表中沒有匹配項(xiàng),用NULL代替
依然沿用內(nèi)鏈接的例子,只是改為右連接
(1)使用右連接查詢學(xué)生的信息,其中包括學(xué)生ID,學(xué)生姓名和專業(yè)名稱。
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students RIGHT JOIN MajorsON Students.MajorID = Majors.ID

通過結(jié)果可以看到,包含了第二張表Majors的全集,Computer在Students表中沒有匹配項(xiàng),就用NULL代替。
3)FULL JOIN (FULL OUTER JOIN,全外連接)
全外連接,簡稱:全連接。會把兩個(gè)表所有的行都顯示在結(jié)果表中
1)使用全連接查詢學(xué)生的信息,其中包括學(xué)生ID,學(xué)生姓名和專業(yè)名稱。
SELECT Students.ID,Students.Name,Majors.Name AS MajorNameFROM Students FULL JOIN MajorsON Students.MajorID = Majors.ID

包含了兩張表的所有記錄,沒有記錄丟失,沒有匹配的行用NULL代替。
4、CROSS JOIN(交叉連接)
交叉連接。交叉連接返回左表中的所有行,左表中的每一行與右表中的所有行組合。交叉連接也稱作笛卡爾積。
簡單查詢兩張表組合,這是求笛卡兒積,效率最低。
笛卡兒積:笛卡爾乘積,也叫直積。假設(shè)集合A={a,b},集合B={0,1,2},則兩個(gè)集合的笛卡爾積為{(a,0),(a,1),(a,2),(b,0),(b,1), (b,2)}??梢詳U(kuò)展到多個(gè)集合的情況。類似的例子有,如果A表示某學(xué)校學(xué)生的集合,B表示該學(xué)校所有課程的集合,則A與B的笛卡爾積表示所有可能的選課情況。
1)交叉連接查詢學(xué)生的信息,其中包括學(xué)生ID,學(xué)生姓名和專業(yè)名稱。
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students CROSS JOIN Majors

2)查詢多表,其實(shí)也是笛卡兒積,與CROSS JOIN等價(jià),以下查詢同上述結(jié)果一樣。
這個(gè)可能很常見,但是大家一定要注意了,這樣就查詢了兩張表中所有組合的全集。
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students,Majors
3)加了查詢條件
注意:在使用CROSS JOIN關(guān)鍵字交叉連接表時(shí),因?yàn)樯傻氖莾蓚€(gè)表的笛卡爾積,因而不能使用ON關(guān)鍵字,只能在WHERE子句中定義搜索條件。
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students CROSS JOIN Majors
WHERE Students.MajorID = Majors.ID

查詢結(jié)果與INNER JOIN一樣,但是其效率就慢很多了。
5.全部示例腳本
CREATE DATABASE TestDB
USE TestDB
------------------------------------------
--創(chuàng)建相關(guān)表
IF OBJECT_ID('Students','U') IS NOT NULL
DROP TABLE Students
--學(xué)生信息表
CREATE TABLE Students(
ID int primary key not null,
Name nvarchar(50),
Age int,
City nvarchar(50),
MajorID int
)
--專業(yè)信息表
IF OBJECT_ID('Majors','U') IS NOT NULL
DROP TABLE Majors
CREATE TABLE Majors(
ID int primary key not null,
Name nvarchar(50)
)
--教師信息表
IF OBJECT_ID('Teachers','U') IS NOT NULL
DROP TABLE Teachers
CREATE TABLE Teachers(
ID int primary key not null,
Name nvarchar(20) not null
)
--預(yù)置數(shù)據(jù)
DELETE FROM Students
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(101,'Tom',20,'BeiJing',10)
INSERT INTO Students(ID,Name,Age,City,MajorID) VALUES(102,'Lucy',18,'ShangHai',11)
DELETE FROM Majors
INSERT INTO Majors(ID,Name) VALUES(10,'English')
INSERT INTO Majors(ID,Name) VALUES(12,'Computer')
DELETE FROM Teachers
INSERT INTO Teachers(ID,Name) VALUES(101,'Mrs Lee')
INSERT INTO Teachers(ID,Name) VALUES(102,'Lucy')
SELECT ID,Name FROM Students
UNION
SELECT ID,Name FROM Teachers
SELECT ID,Name FROM Students
UNION ALL
SELECT ID,Name FROM Teachers
--內(nèi)連接
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students INNER JOIN Majors
ON Students.MajorID = Majors.ID
--左連接
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students LEFT JOIN Majors
ON Students.MajorID = Majors.ID
--右連接
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students LEFT JOIN Majors
ON Students.MajorID = Majors.ID
--全連接
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students FULL JOIN Majors
ON Students.MajorID = Majors.ID
--交叉連接
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students CROSS JOIN Majors
--交叉連接
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students CROSS JOIN Majors
WHERE Students.MajorID = Majors.ID
--一次查詢多表
SELECT Students.ID,Students.Name,Majors.Name AS MajorName
FROM Students,Majors
@ 晴-2017-04-21 18:07:25