摘要:本文對(duì)SQL語(yǔ)言中的自身連接進(jìn)行了詳細(xì)的論述,討論了自身連接存在的必要性,并通過實(shí)例對(duì)SQL中自身連接查詢進(jìn)行了深入的剖析。
關(guān)鍵詞:SQL 自連接 連接查詢
一、連接查詢
在SQL中,如果一個(gè)查詢同時(shí)涉及到兩個(gè)以上的表,那么這種查詢就稱為連接查詢。連接有多種形式,有等值連接、自然連接、非等值連接、外連接、復(fù)合條件連接和自身連接等。
大多數(shù)的連接,都是涉及到不同的表,以下面的SQL代碼為例:
SELECT Student.SNumber, Student.SName, StuCour.*
FROM Student, StuCour
WHERE Student.SNumber=StuCour.SNumber;
在上面的SQL代碼中,有兩個(gè)表:學(xué)生信息表Student(SNumber, SName, SSex, SAge)和學(xué)生選課信息表StuCour(SNumber, CNumber, Grade),這兩個(gè)表都有一個(gè)代表學(xué)生學(xué)號(hào)的叫做SNumber的屬性。查詢結(jié)果是將Student表和StuCour表中SNumber相同的學(xué)生的學(xué)號(hào)、姓名和選課信息顯示出來。
這種連接查詢,使用多個(gè)表格,并利用了不同表格中相應(yīng)的列的邏輯關(guān)系,SQL代碼簡(jiǎn)單、清楚、明了。但連接操作,并不只存在于多個(gè)表之中,有時(shí),對(duì)單表進(jìn)行查詢操作時(shí),也必須使用連接操作。
二、用SQL自連接查詢處理列之間的關(guān)系
SQL自身連接,可以解決很多問題。下面舉的一個(gè)例子,就是使用了SQL自身連接,它解決了列與列之間的邏輯關(guān)系問題,準(zhǔn)確的講是列與列之間的層次關(guān)系。SQL代碼如下:
SELECT FIRST.CNumber, SECOND.PCNumber
FROM Course FIRST, Course SECOND
WHERE FIRST.PCNumber=SECOND.CNumber;
在這個(gè)代碼中,只涉及到一個(gè)表,即課程信息表COURSE(CNumber, CName, PCNumber),其中CNumber是該課程的課程號(hào),PCNumber是該課程的先修課課程號(hào)。在FROM子句中,為Course表起了兩個(gè)不同的別名,即FIRST和SECOND,即為Course表創(chuàng)建了兩個(gè)不同的實(shí)例。查詢時(shí),使用了條件語(yǔ)句WHERE,要求FIRST表中的先修課號(hào)PCNumber同SECOND表中的課程號(hào)CNumber相同,而查詢所需要的結(jié)果,是FIRST表的課程號(hào)CNumber和SECOND表中的PCNumber,那么查詢結(jié)果,就應(yīng)該是FIRST表中的課程號(hào)CNumber和該課程號(hào)所對(duì)應(yīng)的間接先修課課程號(hào)。

同樣的查詢,如果不使用自連接,而純粹是對(duì)單表本身進(jìn)行操作,那將是非常困難的。假設(shè)在這個(gè)表中,有兩個(gè)元組(cnumber1, cname1, pcnumber1)和(cnumber2, cname2, pcnumber2),其中,pcnumber1=cnumber2。在同一個(gè)COURSE表上,關(guān)于課程號(hào)的信息,只有CNumber和PCNumber這兩個(gè)屬性,它們只能表示一個(gè)課程號(hào)(cnumber1)和該課程號(hào)直接先修課(pcnumber1=cnumber2)的一層關(guān)系。而間接先修課,需要求出cnumber1和pcnumber2的關(guān)系,這是一個(gè)二層關(guān)系。對(duì)于這個(gè)只能表示一層關(guān)系的表而言,如果純粹對(duì)單表進(jìn)行操作而不使用自然連接,那么一個(gè)可行的方案是,為Course表再增加一個(gè)列PPCNumber,令該列表示間接先修課,那么,通過三個(gè)列,就可以表示這種二層關(guān)系了。
通過這個(gè)例子以及對(duì)這個(gè)例子的分析,我們可以初步得出結(jié)論,自連接查詢,可以表示表中各列的層次關(guān)系。當(dāng)所要查詢的信息都出于同一個(gè)表,而又不能直接通過該表的各個(gè)列的直接層次關(guān)系得到最終結(jié)果的時(shí)候,那么應(yīng)該考慮使用表的自連接查詢。
三、SQL自連接查詢表示其它關(guān)系
除了處理前面例子中的列之間的層次關(guān)系之外,SQL自連接查詢還可用于處理列之間的順序關(guān)系、因果關(guān)系等多種邏輯關(guān)系。此外,SQL自身查詢還可以用于處理單列本身的邏輯關(guān)系。下面的例子,就說明了對(duì)單列的邏輯關(guān)系的處理。
SELECT FIRST.Num, FIRST Stop, SECOND.Stop
FROM Route FIRST, Route SECOND
WHERE FIRST.NUM=SECOND.NUM;
這個(gè)代碼中,只涉及到一個(gè)表Route(Num, Stop),這個(gè)表可以表示某一線路的火車的車站線路信息。Num表示該車的車次號(hào),Stop表示該次車停靠的城市名稱。上面的代碼,可以求出某一線路的火車可以聯(lián)通的任意兩個(gè)城市的名稱。

在這里例子中,連接的操作對(duì)象只有Num這一個(gè)列,通過相同的車次號(hào),找出該列車聯(lián)通的任意兩個(gè)城市的信息。在這個(gè)例子中,原來表Route中的每一個(gè)元組,只能表示車號(hào)和該車的某一站點(diǎn)的信息,實(shí)際上,這是“1Vs1”的映射關(guān)系。如果要表示兩個(gè)站點(diǎn)的聯(lián)通關(guān)系,那么就應(yīng)該把兩個(gè)“1Vs1”關(guān)系合并,形成“1Vs多”的關(guān)系。我們利用自連接,很容易地解決了這個(gè)關(guān)系擴(kuò)充的問題。
下面的這里例子,是對(duì)單一的列進(jìn)行連接處理:
SELECT FIRST.Num, SECOND.Num, FIRST.Stop
FROM Route FIRST, Route SECOND
WHERE FRIST.Stop=SECOND.Stop;

上面的SQL代碼,求出了路經(jīng)相同城市的車次的信息。原表中的車次和車站是“1Vs1”關(guān)系,通過自連接后,得到了車次和車站的“多Vs1”關(guān)系。
總結(jié)
同其它連接相比,SQL自連接查詢本身并沒有什么特殊的。但是,在應(yīng)用中,自連接查詢因?yàn)槠湔Z(yǔ)法結(jié)構(gòu)簡(jiǎn)單,而邏輯結(jié)構(gòu)復(fù)雜,語(yǔ)義往往不是那么容易被人理解,因此,在使用時(shí),經(jīng)常令人覺得迷惑不解。但只要把自連接運(yùn)用的得當(dāng),把單表看成是多表,牢固樹立這一思維定式,我們會(huì)發(fā)現(xiàn),自連接查詢會(huì)為我們解決很多復(fù)雜的問題。
參考文獻(xiàn):
[1]何明. 從實(shí)踐中學(xué)習(xí)ORACLE/SQL. 清華大學(xué)出版社.
[2]施伯樂,丁寶康. 數(shù)據(jù)庫(kù)系統(tǒng)教程. 高等教育出版社.
[3]王海亮,張立民,王海鳳,鄭建茹.精通Oracle 10g SQL和PL/SQL. 中國(guó)水利水電出版社.