1 創(chuàng)建高級(jí)聯(lián)結(jié)(別名、自聯(lián)結(jié)、外聯(lián)結(jié))
1.1 使用表別名AS
使用別名的兩個(gè)主要理由:
- 縮短SQL語(yǔ)句。
- 允許在一條SELECT語(yǔ)句中多次使用相同的表。
SELECT cust_name, cust_contact
FROM Customers AS C, Orders AS O, OrderItems AS OI
WHERE C.cust_id = O.cust_id
AND OI.order_num = O.order_num
AND prod_id = 'RGAN01';
別名不僅能用于WHERE子句,還可以用于SELECT列表、ORDER BY子句以及其他語(yǔ)句部分。
1.2 使用不同類型的聯(lián)結(jié)
除了內(nèi)聯(lián)結(jié)INNER JOIN之外,還有三種其他聯(lián)結(jié)方式:自聯(lián)結(jié)(self-join)、自然聯(lián)結(jié)(natural join)和外聯(lián)結(jié)(outer join)。
1.2.1 自聯(lián)結(jié)self-join
自聯(lián)結(jié)指的是要檢索的兩個(gè)表實(shí)際上是同一個(gè)表。
假如要給與Jim Jones同一公司的所有顧客發(fā)送一份郵件。
方法一:子查詢
SELECT cust_id, cust_name, cust_contact
FROM Customers
WHERE cust_name = ( SELECT cust_name
FROM Customers
WHERE cust_contact = 'Jim Jones');
方法二:自聯(lián)結(jié)查詢
SELECT c1.cust_id, c1.cust_name, c1.cust_contact
FROM Customers AS c1, Customers AS c2
WHERE c1.cust_name = c2.cust_name
AND c2.cust_contact = 'Jim Jones';
一般來(lái)說(shuō),許多DBMS處理聯(lián)結(jié)遠(yuǎn)比處理子查詢快得多。


1.2.2 自然聯(lián)結(jié)natural join
在對(duì)表進(jìn)行聯(lián)結(jié)時(shí),至少有一列(被聯(lián)結(jié)的列)不止出現(xiàn)在一個(gè)表中。標(biāo)準(zhǔn)的內(nèi)聯(lián)結(jié)返回所有數(shù)據(jù),相同的列甚至多次出現(xiàn)。自然聯(lián)結(jié)排除多次出現(xiàn),使每一列只返回一次。
自然聯(lián)結(jié)要求只能選擇那些唯一的列,一般通過(guò)對(duì)一個(gè)表使用通配符(SELECT *),而對(duì)其他表的列使用明確的子集來(lái)完成。
SELECT C.*, O.order_num, O.order_date,
OI.prod_id, OI.quantity, OI.item_price
FROM Customers AS C, Orders AS O, OrderItems AS OI
WHERE C.cust_id = O.cust_id
AND OI.order_num = O.order_num
AND prod_id = 'RGAN01';

在這個(gè)例子中,通配符只對(duì)第一個(gè)表使用。所有其他列明確列出,所以沒(méi)有重復(fù)的列被檢索出來(lái)。
事實(shí)上,我們迄今為止建立的每個(gè)內(nèi)聯(lián)結(jié)都是自然聯(lián)結(jié),很可能永遠(yuǎn)都不會(huì)用到不是自然聯(lián)結(jié)的內(nèi)聯(lián)結(jié)。
1.2.3 外聯(lián)結(jié)outer join
許多聯(lián)結(jié)將一個(gè)表中的行與另一個(gè)表中的行相關(guān)聯(lián),但有時(shí)候需要包含沒(méi)有關(guān)聯(lián)的那些行。
例如:
- 對(duì)每個(gè)顧客下的訂單進(jìn)行計(jì)數(shù),包括哪些至今尚未下訂單的顧客。
- 列出所有產(chǎn)品以及訂購(gòu)數(shù)量,包括沒(méi)有人訂購(gòu)的產(chǎn)品。
- 計(jì)算平均銷售規(guī)模,包括哪些至今尚未下訂單的顧客。
在上述例子中,聯(lián)結(jié)包含了那些在相關(guān)表中沒(méi)有關(guān)聯(lián)行的行,這種聯(lián)結(jié)稱為外聯(lián)結(jié)(outer join)。
內(nèi)聯(lián)結(jié)檢索所有顧客及其訂單:
SELECT Customers.cust_id, Orders.order_num
FROM Customers INNER JOIN Orders
ON Customers.cust_id = Orders.cust_id;

外聯(lián)結(jié)語(yǔ)法類似,檢索包括沒(méi)有訂單顧客在內(nèi)的所有顧客:
SELECT Customers.cust_id, Orders.order_num
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;

使用OUTER JOIN語(yǔ)法時(shí),必須使用RIGHT或LEFT關(guān)鍵字指定包括其所有行的表(RIGHT指出的是OUTER JOIN右邊的表,而LEFT指出的是OUTER JOIN左邊的表)。
上面的例子使用LEFT OUTER JOIN從FROM子句左邊的表(Customers表)中選擇所有行。為了從右邊的表中選擇所有行,需要使用RIGHT OUTER JOIN,如下例所示。
SELECT Customers.cust_id, Orders.order_num
FROM Customers RIGHT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;

還存在另一種外聯(lián)結(jié),就是全外聯(lián)結(jié)(full outer join),它檢索兩個(gè)表中的所有行并關(guān)聯(lián)那些可以關(guān)聯(lián)的行,全外聯(lián)結(jié)包含了兩個(gè)表中的不關(guān)聯(lián)的行。(Access、MariaDB、MySQL和SQLite不支持FULL OUTER JOIN語(yǔ)法)
SELECT Customers.cust_id, Orders.order_num
FROM Customers FULL OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id;
1.3 使用帶聚集函數(shù)的聯(lián)結(jié)
檢索所有顧客及每個(gè)顧客所下的訂單數(shù):
SELECT Customers.cust_id,
COUNT(Orders.order_num) AS num_ord
FROM Customers INNER JOIN Orders
ON Customers.cust_id = Orders.cust_id
GROUP BY Customers.cust_id;

聚集函數(shù)也可以方便地與其他聯(lián)結(jié)一起使用。
SELECT Customers.cust_id,
COUNT(Orders.order_num) AS num_ord
FROM Customers LEFT OUTER JOIN Orders
ON Customers.cust_id = Orders.cust_id
GROUP BY Customers.cust_id;

1.4 使用聯(lián)結(jié)和聯(lián)結(jié)條件
- 注意所使用的聯(lián)結(jié)類型。一般我們使用內(nèi)聯(lián)結(jié),但使用外聯(lián)結(jié)也有效。
- 保證使用正確的聯(lián)結(jié)條件,否則會(huì)返回不正確的數(shù)據(jù)。
- 應(yīng)該總是提供聯(lián)結(jié)條件,否則會(huì)得出笛卡爾積。
- 在一個(gè)聯(lián)結(jié)中可以包含多個(gè)表,甚至可以對(duì)每個(gè)聯(lián)結(jié)采用不同的聯(lián)結(jié)類型。雖然這樣做是合法的,一般也很有用,但應(yīng)該在一起測(cè)試它們前分別測(cè)試每個(gè)聯(lián)結(jié),這會(huì)使故障排除更為簡(jiǎn)單。
2 組合查詢(UNION)
2.1 組合查詢
多數(shù)SQL查詢只包含從一個(gè)或多個(gè)表中返回?cái)?shù)據(jù)的單條SELECT語(yǔ)句,但是SQL也允許執(zhí)行多個(gè)查詢(多條SELECT語(yǔ)句),并將結(jié)果作為一個(gè)查詢結(jié)果集返回。這些組合查詢通常稱為并(union)或復(fù)合查詢(compound query)。
使用組合查詢的兩個(gè)主要情況:
- 在一個(gè)查詢中從不同的表返回結(jié)構(gòu)數(shù)據(jù)。
- 對(duì)一個(gè)表執(zhí)行多個(gè)查詢,按一個(gè)查詢返回?cái)?shù)據(jù)。
2.2 創(chuàng)建組合查詢
可用UNION操作符來(lái)組合數(shù)條SQL查詢,利用UNION,可給出多條SELECT語(yǔ)句,將它們的結(jié)果組合成一個(gè)結(jié)果集。
2.2.1 使用UNION
給出每條SELECT語(yǔ)句,在各條語(yǔ)句之間放上關(guān)鍵字UNION。
例如,需要Illinois、Indiana和Michigan等美國(guó)幾個(gè)州的所有顧客的報(bào)表,還想包括不管位于哪個(gè)州的所有的Fun4All。當(dāng)然可以利用WHERE子句來(lái)完成此工作,不過(guò)這次我們使用UNION。
使用WHERE語(yǔ)句:
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
OR cust_name = 'Fun4All';

使用UNION語(yǔ)句:
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';

在這個(gè)簡(jiǎn)單的例子中,使用UNION可能比使用WHERE子句更為復(fù)雜。但對(duì)于較復(fù)雜的過(guò)濾條件,或者從多個(gè)表(而不是一個(gè)表)中檢索數(shù)據(jù)的情形,使用UNION可能會(huì)使處理更簡(jiǎn)單。
2.2.2 UNION規(guī)則
- UNION必須由兩條或兩條以上的SELECT語(yǔ)句組成,語(yǔ)句之間用關(guān)鍵字UNION分隔。如果組合四條SELECT語(yǔ)句,將要使用三個(gè)UNION關(guān)鍵字。
- UNION中的每個(gè)查詢必須包含相同的列、表達(dá)式或聚集函數(shù),各個(gè)列不需要以相同的次序列出。
- 列數(shù)據(jù)類型必須兼容:類型不必完全相同,但必須是DBMS可以隱含轉(zhuǎn)換的類型(例如,不同的數(shù)值類型或不同的日期類型)。
2.2.3 包含或取消重復(fù)的行
UNION從查詢結(jié)果集中自動(dòng)去除了重復(fù)的行,它的行為與一條SELECT語(yǔ)句中使用多個(gè)WHERE子句條件一樣。使用UNION時(shí),重復(fù)的行會(huì)自動(dòng)取消。
如果想返回所有的匹配行,可使用UNION ALL而不是UNION。
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION ALL
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All';

2.2.4 對(duì)組合查詢結(jié)果排序
在用UNION組合查詢時(shí),只能使用一條ORDER BY子句,它必須位于最后一條SELECT語(yǔ)句之后。
對(duì)于結(jié)果集,不存在用一種方式排序一部分,而又用另一種方式排序另一部分的情況,因此不允許使用多條ORDER BY子句。
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_state IN ('IL','IN','MI')
UNION
SELECT cust_name, cust_contact, cust_email
FROM Customers
WHERE cust_name = 'Fun4All'
ORDER BY cust_name, cust_contact;

雖然ORDER BY子句似乎只有最后一條SELECT語(yǔ)句的組成部分,但實(shí)際上DBMS將用它來(lái)排序所有SELECT語(yǔ)句返回的所有結(jié)果。
如果您發(fā)現(xiàn)文中有不清楚或者有問(wèn)題的地方,請(qǐng)?jiān)谙路皆u(píng)論區(qū)留言,我會(huì)根據(jù)您的評(píng)論,更新文中相關(guān)內(nèi)容,謝謝!