SQL連接查詢研究

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:


image.png

B:


image.png

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

結果:


image.png

分析:

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

結果:


image.png

分析:
從結果可以看出,雖然合同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

結果:


image.png

結果滿足我們的需求,但是如果把篩選條件放在on中:

SELECT
    *
FROM
    contract a
LEFT JOIN contract_history b ON a.id = b.fk_contract_id
AND b.hi_contract_amount = 300

結果:


image.png

顯然,查詢結果不滿足我們的這個需求!
栗子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

結果:


image.png

連接條件同樣需要注意位置,可總結為:
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ù):


image.png

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


image.png

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

結果:


image.png

分析:
從結果中可以看出,全連接會返回A、B表中所有記錄,其中有關聯(lián)的會根據(jù)on條件進行整合,沒有連接上的記錄也會返回。

總結:
SQL中的連接查詢使用非常頻繁,但其中的一些細節(jié)還需要平時多注意,比如:
1、左、右連接時的條件放置位置及其區(qū)別;
2、一對多關系時,在左、右外連接時,若“一”為主表(或內連接)時,查詢結果集主表記錄會有重復!若要統(tǒng)計主表記錄時則需去重。

以上是筆者在平時工作中用到sql的連接查詢時總結出來的知識,分享給大家,希望對讀者有幫助!如有錯誤請給我留言,我會及時更正,謝謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容