1、分類
在多表關聯(lián)查詢時,經(jīng)常要用到連接查詢,SQL中連接分為四種:內連接(inner join或join)、左外連接(left outer join)、右外連接(right outer join)、全連接(full outer join);
其中,除了inner join其余三種都是外連接。
首先建2張表用于后面的講解用。
表A:合同表
CREATE TABLE `contract` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '合同表主鍵ID',
`contract_name` varchar(255) DEFAULT NULL COMMENT '合同名稱',
`contract_no` varchar(200) DEFAULT NULL COMMENT '合同編號',
`contract_amount` decimal(11,2) DEFAULT NULL COMMENT '合同金額',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
表B:合同金額歷史修改記錄表
CREATE TABLE `contract_history` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '歷史合同金額表主鍵ID',
`fk_contract_id` int(10) NOT NULL COMMENT '合同ID',
`hi_contract_amount` decimal(10,2) DEFAULT NULL COMMENT '合同歷史金額',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
其中,B表中的fk_contract_id字段與A表中的id字段有外鍵關系;
2、inner join內連接
內連接結果返回A、B兩個表均匹配的數(shù)據(jù)集,其中有一個表的數(shù)據(jù)不滿足,則那條數(shù)據(jù)不返回;
模擬數(shù)據(jù)如下:
A:

B:

內連接查詢:
select * from contract a INNER JOIN contract_history b on a.id=b.fk_contract_id
結果:

分析:
1、A表中合同3的數(shù)據(jù)并沒有查詢出來,因為B表中沒有對應的記錄;
2、合同1的數(shù)據(jù)查出2條了,因為B表中顯示合同1修改過2次合同金額了,因此可以看出,當A、B表是一對多的關系時,因inner join沒有主從表之分,因此只要A、B表按照連接條件能夠匹配的數(shù)據(jù)都會返回,其中,“一對多”關系中的“一”表數(shù)據(jù)會有重復,因此使用時需要注意這一點!
3、內連接時,篩選條件放在連接條件on中和放在where中查詢的結果集是一致的,但是效率上會有區(qū)別,一般來說,放在on中效率更高一些。
3、left outer join左外連接
通常也簡稱為左連接,sql中可省略outer,寫為:left join;
左連接以左表為主表,右表為從表,返回結果集以左表數(shù)據(jù)為基礎,連接右表獲取額外信息;
查詢語句舉例:
select * from contract a LEFT JOIN contract_history b on a.id=b.fk_contract_id
結果:

分析:
從結果可以看出,雖然合同3在B表中沒有數(shù)據(jù)與之對應,但是還是作為結果集中的一部分返回了,因此可以這么說,只要主表有N條記錄,使用left join查詢返回的結果集一定至少有N條記錄(不考慮where條件)!
這里需要注意:如果A表與B表為一對多關系,查詢結果記錄數(shù)會大于主表(A表)記錄數(shù),例如上圖中,合同1的記錄就有2條;
特別注意左連接時查詢條件放置的位置:
使用left join查詢時,主表的篩選條件要放在where中,而從表的條件要看情況選擇放在連接條件on中或是放在where中;下面舉例子說明這兩種情況:
栗子1:查詢出所有歷史合同金額有過300的合同記錄。
sql:
SELECT
*
FROM
contract a
LEFT JOIN contract_history b ON a.id = b.fk_contract_id
WHERE
b.hi_contract_amount = 300
結果:

結果滿足我們的需求,但是如果把篩選條件放在on中:
SELECT
*
FROM
contract a
LEFT JOIN contract_history b ON a.id = b.fk_contract_id
AND b.hi_contract_amount = 300
結果:

顯然,查詢結果不滿足我們的這個需求!
栗子2:查詢出所有合同,并且如果其歷史合同金額有過300則展示其合同記錄信息。
在這個需求下,我們把查詢條件放在on中就是正確的,這時是不能放在where中的。
4、right outer join右外連接
通常簡稱為右連接,outer可省略,寫為:right join;
與左連接相反,右連接以右表為主表,即以右表記錄為基礎,擴展查詢左表信息;
一般可與左連接相互轉換,例如上栗1用右連接可以寫成如下sql:
SELECT
*
FROM
contract_history a
RIGHT JOIN contract b ON a.fk_contract_id = b.id
WHERE
a.hi_contract_amount = 300
結果:

連接條件同樣需要注意位置,可總結為:
1、主表條件放在where中,從表條件按照需求選擇放在on中或是where中!
2、當從表條件放在on中時,該條件不影響返回的結果集記錄數(shù),但是放在where中則會篩選主表記錄!
5、full outer join全連接
全連接,即只要其中某個表存在匹配,full join關鍵字就會返回行。在mysql中并不支持full join,但可以用left join和right join查詢后再union代替,舉個栗子:
A表數(shù)據(jù):

B表數(shù)據(jù):

sql:
SELECT
*
FROM
contract a
LEFT JOIN contract_history b ON b.fk_contract_id = a.id
UNION
SELECT
*
FROM
contract a
RIGHT JOIN contract_history b ON b.fk_contract_id = a.id
結果:

分析:
從結果中可以看出,全連接會返回A、B表中所有記錄,其中有關聯(lián)的會根據(jù)on條件進行整合,沒有連接上的記錄也會返回。
總結:
SQL中的連接查詢使用非常頻繁,但其中的一些細節(jié)還需要平時多注意,比如:
1、左、右連接時的條件放置位置及其區(qū)別;
2、一對多關系時,在左、右外連接時,若“一”為主表(或內連接)時,查詢結果集主表記錄會有重復!若要統(tǒng)計主表記錄時則需去重。
以上是筆者在平時工作中用到sql的連接查詢時總結出來的知識,分享給大家,希望對讀者有幫助!如有錯誤請給我留言,我會及時更正,謝謝!