您的位置:首页 > 数据库 > Oracle

ORACLE的SQL JOIN方式小结

2016-10-07 12:13 441 查看
在ORACLE数据库中,表与表之间的SQLJOIN方式有多种(不仅表与表,还可以表与视图、物化视图等联结),官方的解释如下所示Ajoinisaquerythatcombinesrowsfromtwoormoretables,views,ormaterializedviews.OracleDatabaseperformsajoinwhenevermultipletablesappearintheFROMclauseofthequery.Theselectlistofthequerycanselectanycolumnsfromanyofthesetables.Ifanytwoofthesetableshaveacolumnnameincommon,thenyoumustqualifyallreferencestothesecolumnsthroughoutthequerywithtablenamestoavoidambiguity.SQLJOIN归纳起来有下面几种方式,下面一起来梳理一下这些概念。SQLJOIN其实是一个逻辑概念,像NESTLOOPJOIN、HASHJOIN等是表连接的物理实现方式。



我们先准备一个两个测试表M与N(仅仅是为了演示需要),如下脚本所示

SQL>CREATETABLEM
2(
3NAMEVARCHAR2(12)
4,SEXVARCHAR2(6)
5);
Tablecreated.
SQL>CREATETABLEN
2(
3NAMEVARCHAR2(12)
4,GRADENUMBER(2)
5);
Tablecreated.
SQL>INSERTINTOM
2SELECT'kerry','male'FROMDUALUNIONALL
3SELECT'jimmy','male'FROMDUALUNIONALL
4SELECT'tina','female'FROMDUALUNIONALL
5SELECT'wendy','female'FROMDUAL;
4rowscreated.
SQL>COMMIT;
Commitcomplete.
SQL>INSERTINTON
2SELECT'kerry',3FROMDUALUNIONALL
3SELECT'jimmy',2FROMDUALUNIONALL
4SELECT'ken',6FROMDUALUNIONALL
5SELECT'richard',5FROMDUAL;
4rowscreated.
SQL>COMMIT;
Commitcomplete.

内连接:INNERJOIN
INNERJOIN它表示返回两个表或记录集连接字段的匹配记录。如下所示,INNERJOIN可以有三种实现方式:

SQL>SELECTM.NAME,M.SEX,N.GRADE
2FROMMINNERJOINNONM.NAME=N.NAME;
NAMESEXGRADE
----------------------------
kerrymale3
jimmymale2
SQL>SELECTM.NAME,M.SEX,N.GRADE
2FROMM,N
3WHEREM.NAME=N.NAME;
NAMESEXGRADE
----------------------------
kerrymale3
jimmymale2


第三种方式,使用USING,如下所示,这种写法一般较少人使用。

SQL>SELECTNAME,M.SEX,N.GRADE
2FROMMINNERJOINNUSING(NAME);
NAMESEXGRADE
----------------------------
kerrymale3
jimmymale2
SQL>




注意,INNERJOIN可以用使用简写JOIN方式,如下所示,但是建议使用INNERJOIN而不是JOIN这样的语法。



如果我们用韦恩图来解释INNERJOIN,则非常一目了然、形象生动。可以用下面图来表示(此图以及下面的韦恩图均来自链接http://pafumi.net/SQL_Joins.html,本来想自己画,无奈有些图使用word不好实现,R语言不会。故在此借其图用用)




外连接:OUTERJOIN

1全连接:fulljoin

全连接:包含左、右两个表的全部行,不管另外一边的表中是否存在与它们匹配的行。不符合条件的,以空值代替。如下所示:

SQL>SELECTM.NAME,N.NAME,M.SEX,N.GRADE
2FROMMFULLOUTERJOINNONM.NAME=N.NAME;
NAMENAMESEXGRADE
----------------------------------------
kerrykerrymale3
jimmyjimmymale2
ken6
richard5
tinafemale
wendyfemale
6rowsselected.




FULLOUTERJOIN的韦恩图如下所示:



2左外连接:LEFTJOIN

左外连接又叫左连接:意思是包含左边表所有记录,右边所有的匹配的记录,如果没有则用空补齐。换句话说就是,列出左边表全部的,及右边表符合条件的,不符合条件的以空值代替。

SQL>SELECTM.NAME,N.NAME,M.SEX,N.GRADE
2FROMMLEFTOUTERJOINNONM.NAME=N.NAME;
NAMENAMESEXGRADE
----------------------------------------
kerrykerrymale3
jimmyjimmymale2
tinafemale
wendyfemale
SQL>SELECTM.NAME,N.NAME,M.SEX,N.GRADE
2FROMMLEFTJOINNONM.NAME=N.NAME;
NAMENAMESEXGRADE
----------------------------------------
kerrykerrymale3
jimmyjimmymale2
tinafemale
wendyfemale


在ORACLE9i以及之前,使用在(+)来表示左连接,哪个带(+)哪个需要条件符合的,另一个全部的。即放左表示右连接,放右表示左连接。这种写法,如果不熟悉,就会有点陌生。其实也不是什么新鲜事物,只是你不太熟悉而已。

SQL>SELECTM.NAME,N.NAME,M.SEX,N.GRADE
2FROMM,N
3WHEREM.NAME=N.NAME(+);
NAMENAMESEXGRADE
----------------------------------------
kerrykerrymale3
jimmyjimmymale2
tinafemale
wendyfemale
SQL>




LEFTOUTERJOIN的韦恩图如下所示:



3右外连接:RIGHTJOIN

右外连接又叫右连接:意思是包括右边表所有记录,匹配左边表的记录,如果没有则以空补齐,换句话说,与左连接一样,列出右边表全部的,及左边表符合条件的,不符合条件的用空值替代。如下所示

SQL>SELECTM.NAME,N.NAME,M.SEX,N.GRADE
2FROMMRIGHTOUTERJOINNONM.NAME=N.NAME;
NAMENAMESEXGRADE
----------------------------------------
kerrykerrymale3
jimmyjimmymale2
ken6
richard5
SQL>SELECTM.NAME,N.NAME,M.SEX,N.GRADE
2FROMMRIGHTJOINNONM.NAME=N.NAME;
NAMENAMESEXGRADE
----------------------------------------
kerrykerrymale3
jimmyjimmymale2
ken6
richard5
SQL>SELECTM.NAME,N.NAME,M.SEX,N.GRADE
2FROMM,N
3WHEREM.NAME(+)=N.NAME;
NAMENAMESEXGRADE
----------------------------------------
kerrykerrymale3
jimmyjimmymale2
ken6
richard5




笛卡尔积:CROSSJOIN
CROSSJOIN就是笛卡尔乘积连接,不需要任何关联条件,实现M*N的结果集,其实这种SQLJOIN方式基本上只在理论上有意义,实际当中,很少有用的CORSSJOIN方式。
注意:crossjoin跟innerjoin、outerjoin等有所不同,不需要关键词on,因为它不需要相关字段做关联。

SQL>SELECTM.NAME,M.SEX,N.NAME,N.GRADE
2FROMMCROSSJOINN;
NAMESEXNAMEGRADE
----------------------------------------
kerrymalekerry3
kerrymalejimmy2
kerrymaleken6
kerrymalerichard5
jimmymalekerry3
jimmymalejimmy2
jimmymaleken6
jimmymalerichard5
tinafemalekerry3
tinafemalejimmy2
tinafemaleken6
NAMESEXNAMEGRADE
----------------------------------------
tinafemalerichard5
wendyfemalekerry3
wendyfemalejimmy2
wendyfemaleken6
wendyfemalerichard5
16rowsselected.




注意:笛卡尔积用维恩图是无法体现出来的。
自然连接:NATURALJOIN
NATURALJOIN:在连接条件中使用等于(=)运算符比较被连接列的列值,但它使用选择列表指出查询结果集合中所包括的列,并删除连接表中的重复列。如下所示

SQL>SELECT*FROMMNATURALJOINN;
NAMESEXGRADE
----------------------------
kerrymale3
jimmymale2

官方解释:
TheNATURALkeywordindicatesthatanaturaljoinisbeingperformed.Anaturaljoinisbasedonallcolumnsinthetwotablesthathavethesamename.Itselectsrowsfromthetwotablesthathaveequalvaluesintherelevantcolumns.Whenspecifyingcolumnsthatareinvolvedinthenaturaljoin,donotqualifythecolumnnamewithatablenameortablealias
有种说法是,对两张表中字段名和数据类型都相同的字段进行等值连接,并返回符合条件的结果,其实只要字段名相同,数据类型不同,也可以做NATURALJOIN,如下所示:

SQL>CREATETABLETEST1
2(
3IDNUMBER(10),
4NAMEVARCHAR2(12)
5);
Tablecreated.
SQL>CREATETABLETEST2
2(
3IDVARCHAR2(10),
4NTVARCHAR2(12)
5);
Tablecreated.
SQL>INSERTINTOTEST1
2VALUES(1000,'KERRY');
1rowcreated.
SQL>COMMIT;
Commitcomplete.
SQL>INSERTINTOTEST2
2VALUES('1000','KKK');
1rowcreated.
SQL>SELECT*FROMTEST1NATURALJOINTEST2;
IDNAMENT
----------------------------------
1000KERRYKKK
SQL>




自然连接的两个表的有多个字段都满足有相同名称,那么他们会被作为自然连接的条件,如下案例所示

SQL>DROPTABLETEST1;
Tabledropped.
SQL>DROPTABLETEST2;
Tabledropped.
SQL>CREATETABLETEST1
2(
3IDNUMBER(10),
4NAMEVARCHAR2(12)
5)
6;
Tablecreated.
SQL>CREATETABLETEST2
2(
3IDNUMBER(10),
4NAMEVARCHAR2(12)
5);
Tablecreated.
SQL>INSERTINTOTEST1
2SELECT1000,'KERRY'FROMDUALUNIONALL
3SELECT1001,'KEN'FROMDUAL;
2rowscreated.
SQL>COMMIT;
Commitcomplete.
SQL>INSERTINTOTEST2
2SELECT1000,'KKK'FROMDUALUNIONALL
3SELECT1001,'KEN'FROMDUAL;
2rowscreated.
SQL>COMMIT;
Commitcomplete.
SQL>SELECT*FROMTEST1NATURALJOINTEST2;
IDNAME
----------------------
1001KEN




NATURALJOIN的韦恩图,其实和内连接是一样的。如下所示:



SEMIJOIN

SEMIJOIN多在子查询exists中使用,对外部rowsource的每个键值,查找到内部rowsource匹配的第一个键值后就返回,如果找到就不用再查找内部rowsource其他的键值了。官方介绍案例如下

UsingSemijoins:Example

Inthefollowingexample,onlyonerowneedstobereturnedfromthedepartmentstable,eventhoughmanyrowsintheemployeestablemightmatchthesubquery.Ifnoindexhasbeendefinedonthesalarycolumninemployees,thenasemijoincanbeusedtoimprovequeryperformance.

SELECT*FROMdepartments

WHEREEXISTS

(SELECT*FROMemployees

WHEREdepartments.department_id=employees.department_id

ANDemployees.salary>2500)

ORDERBYdepartment_name;

ANTIJOIN

ANTIJOIN多用于!=或notin等查询;如果找到满足条件(!=notin)的不返回,不满足条件(!=notin)的返回。和join相反。

UsingAntijoins:Example

Thefollowingexampleselectsalistofemployeeswhoarenotinaparticularsetofdepartments:

SELECT*FROMemployees

WHEREdepartment_idNOTIN

(SELECTdepartment_idFROMdepartments

WHERElocation_id=1700)

ORDERBYlast_name;

SELFJOIN

SELFJOIN其实就是某个表和其自身连接,连接方式可以是内连接,外连接,交叉连接

UsingSelfJoins:Example

Thefollowingqueryusesaselfjointoreturnthenameofeachemployeealongwiththenameoftheemployee'smanager.AWHEREclauseisaddedtoshortentheoutput.

SELECTe1.last_name||'worksfor'||e2.last_name

"EmployeesandTheirManagers"

FROMemployeese1,employeese2

WHEREe1.manager_id=e2.employee_id

ANDe1.last_nameLIKE'R%';

EmployeesandTheirManagers

-------------------------------

RajsworksforMourgos

RaphaelyworksforKing

RogersworksforKaufling

RussellworksforKing

参考资料:
https://docs.oracle.com/cd/B19306_01/server.102/b14200/queries006.htm
http://pafumi.net/SQL_Joins.html
http://www.itpub.net/thread-420946-1-1.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: