一、概述:
1. 多表(连接)查询:
(1) 即查询的时候同时需要多张表(特别是存在外键关系的),此时需要多张表之间的值进行连接;
(2) 目前SQL标准提出过两种连接查询,第一种是较早的SQL92标准,第二种是目前使用广泛的较新的SQL99标准;
(3) 92形式简单,但语句上比较冗杂,外连接不太容易识别;99不仅在底层得到优化,而且形式看上去更加一目了然,逻辑性更强。
(4) 两种方式均可,其中SQL92书写方便阅读困难,SQL99书写较麻烦,但阅读很方便,而且符合逻辑(下文会体现),两种方式都有使用,所以都要学习。
(5) 更推荐SQL99。一般建议使用99标准;
2. SQL语句的历史版本:
SQL89(比较多)
SQL92(标准,又称sql2)
SQL99(标准,又称sql3)
3. 多表连接查询(类型):
--当所需要查询的数据 分布在多张表上时,需要使用多表查询(也称 多表关联查询 /联合查询 /连接查询):
--连接有三种基本类型:交叉连接,内连接,外连接。这三种连接的区别是 它们采用的逻辑查询 处理步骤各不相同:
--交叉连接:只有一个步骤 — 笛卡尔积;
--内连接:有两个步骤 — 笛卡尔积,过滤;
--外连接:有三个步骤 — 笛卡尔积,过滤,添加外部行。
4.多表关联查询包括
交叉连接:
--笛卡尔积
内连接:
--等值关联查询
--非等值关联查询
--自然连接
--自连接
外连接:
--左外连接
--右外连接
--全外连接
5.概念说明:
(1)SQL92标准语法介绍:
1) 多张表需要全部放在from之后,
2) 多张表之间 通过逗号分隔,
3) 所有的连接条件都放在where当中,
--结论:因此SQL92中的 等值连接、非等值链接、外连接 等等 其实只是where中的条件不同罢了;
(2) SQL99标准语法介绍:
0) 通过一系列的关键字 (比如join,on等), 来定义表与表之间的 连接类型 与 连接条件,写法更加符合逻辑,可读性更好,并且底层支持地更好;
1) 基本覆盖了全部类型的连接查询(包括外连接),并且各大数据库都能全部支持SQL99的连接查询;
2) 直接使用关键字:cross join(交叉连接,即广义笛卡尔积)、natrual join(自然连接)、left join/right join(左右外连接)表示连接类型;
3) 直接使用关键字:cross join(交叉连接,即广义笛卡尔积)、natrual join(自然连接)、left join/right join(左右外连接)表示连接类型;
注意:
- 依然可以给表添加别名
- 如果使用on或者using关键字对结果进行筛选必须使用inner join进行表与表的连接,其中inner可以省略
- 外连接的outer关键字可以省略不写
- 依然可以继续使用group by,having,order by等
(3)交叉连接,又称之为 笛卡尔积 (即 SQL92的广义笛卡尔积):
--概念:
1) 两个表做笛卡尔积,得到的结果集的行数 是两个表的 行数的 乘积 (三表/多表同理),效率最低。
2) 即 将两张表的数据 拼接在一起,总记录数为 两张表记录量(行数)的乘积 ( 表*表 );
--语法:
SELECT * FROM 表1 CROSS JOIN 表2; //SQL99标准
SELECT * FROM 表1,表2; //SQL92标准
select ...
from 表1
cross join 表2
[corss join 表3...]
--注1:如果有很多表要交叉连接,那么就继续cross join下去;
--注2:如果select选出的列刚好在各个表中有重名,则需要为表取别名以示区别,否则会显示出同名的两列,不易于区分;示例:
select s.col1, t.col2
from t1 as s
cross join t2 as t;
--注3:一般区别名还是建议使用as,如果一下用太多空格可读性会大大降低!并且as见名知意;
--注4:在实际开发中 这种业务需求 是很少见的,一般不会使用交叉连接,而是 使用具体的条件 对数据进行 有目的的查询;
--注5:数学上,笛卡尔积也称直积,两个集合X和Y的笛卡尓积表示为X × Y,第一个对象是X的成员,而第二个对象是Y的 所有可能有序对的 其中一个成员。例如集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2)}。
--例如:department表中 有4个部门,employee表中 有4个员工,那么交叉连接的结果 就有4 * 4 = 16条数据;
(4) 内连接:又称 简单连接 或 自然连接.
--概念:返回查询结果集合中的仅是符合查询条件的数据行。
--说明:内连接使用比较运算符 (包括 =、>、<、<>、>=、<=、!> 和!< 等) 对两个表 (或多表) 中的数据 进行比较,并列出(/查询出) 与连接条件匹配的数据行,组合成新的记录,也就是说 在内连接查询中,只有满足条件的记录 才能出现在查询结果中。根据所使用的比较方式不同,内连接分为 等值连接、非等值连接、自然连接 和 自连接。
--说明:内连接,只查匹配行;内连接是从结果中删除其他被连接表中没有匹配行的所有行,所以内连接可能会丢失信息。
--语法:
select * from 主表 inner join 附表 on 主表.字段=附表.字段 [where条件] //SQL99标准
--注:用 * 号表示查询两个表中的所有列
select 内容 from 表名 inner join 表名 on 连接条件 where 普通筛选条件 //SQL99标准
--注:普通筛选条件使用where进行筛选,不要使用on进行。好处:SQL语句的阅读性变强。
--例如:已知表结构与测试数据如下
--查询studentInfo表和scoreInfo表中的所有列
select * from studentInfo inner join scoreInfo on studentInfo.stuID = scoreInfo.stuId //SQL99标准
--查询studentInfo表和scoreInfo表中的部分列
SELECT
stu.stuName 姓名,
stu.stuSex 性别,
stu.stuAge 年龄,
stu.className 班级,
sco.score 成绩,
sco.createTime 考试时间
FROM
studentInfo as stu
INNER JOIN
scoreInfo as sco
ON
stu.stuID = sco.stuId
其中as是可以省略的,但一般为了增强可读性,不会对其省略,或者:
SELECT
studentInof.stuName 姓名,
studentInfo.stuSex 性别,
studentInfo.stuAge 年龄,
studentInfo.className 班级,
scoreInfo.score 成绩,
scoreInfo.createTime 考试时间
FROM
studentInfo
INNER JOIN
scoreInfo
ON
studentInfo.stuID = scoreInfo.stuId
(5) 等值连接,也称 等值关联查询:
--概念:先做表的笛卡尔积,然后筛选,筛选条件为等值筛选;
--例如:
SELECT 查询字段 FROM 表1 [INNER] JOIN 表2 ON 表1.关系字段 = 表2.关系字段; //SQL99标准
--注:在上述使用了SQL99标准,语法格式中,INNER JOIN用于连接两个表,ON来指定连接条件,其中INNER可以省略。
SELECT * FROM 表1 inner join 表2 on 表1.关系字段 = 表2.关系字段; //SQL99标准 SELECT * FROM 表1 join 表2 on 表1.关系字段 = 表2.关系字段; //SQL99标准
--注:SQL99标准,有时也被称为 显示内连接:显示的就是在语句中明显的调用了inner join的关键字。
SELECT * FROM 表1,表2 where 表1.关系字段 = 表2.关系字段; //SQL92标准
--注:SQL92标准,有时也被称为 隐式内连接:顾名思义隐式的就是我们看不到inner join的关键字。而使用where关键字替代。
(6) 不等值连接,非等值关联查询:
--概念:先做表的笛卡尔积,然后筛选,筛选条件为不等值连接;
--例如:
SELECT * FROM 表1 inner join 表2 on 表1.关系字段 = 表2.关系字段; //SQL99标准
SELECT * FROM 表1 join 表2 on 表1.关系字段 = 表2.关系字段; //SQL99标准
SELECT * FROM 表1,表2 where 表1.关系字段 = 表2.关系字段; //SQL92标准
--注1:SQL92标准,有时也被称为 隐式内连接:顾名思义隐式的就是我们看不到inner join的关键字。而使用where关键字替代。
--注2:SQL99标准,有时也被称为 显示内连接:显示的就是在语句中明显的调用了inner join的关键字。
(7) 自连接:
(8) 外连接:
1) 与内连接相比,即使没有匹配行,也会返回一个表的全集。
2) 内连接只返回满足连接条件的数据行,外连接除了能显示满足连接条件的数据以外, 还用于显示不满足连接条件的数据;
3) 重点:至少有一方保留全集,另一方 没有匹配行用NULL代替。
4) 外连接分为左外连接、右外链接、全外连接三种。
5) 外连接不仅要把符合条件的连接输出,也要把不符合条件的连接也输出,但不是完整的输出!!!
(9) 左外连接:
(10) 右外连接:
(11) 全外连接:
二、SQL92与SQL99语法详解:
1. SQL92 语法
笛卡尔积
select * from emp e,dept d
等值连接 ( 在where后的条件为等值条件 , 即: “=” )
select * from emp t, dept d where t.deptno = d.deptno;
非等值连接 ( 在where后的条件为非等值条件 , 例如:> , < , >= , <= 等 )
select e.ename,s.grade from emp e, salgrade s where e.sal between s.losal and s.hisal;
自连接 ( 在where后的条件 , 用自身字段之间的关连作为条件 )
select e1.ename,e2.ename from emp e1,emp e2 where e1.mgr = e2.empno;
外连接 (在满足一张表的内容都显示的基础上,连接另外一张表,如果连接匹配则正常显示,连接不匹配,另外一张表补null)
select e.ename,d.dname from emp e, dept d where e.deptno = d.deptno(+) ;
2. SQL 99 语法 :
语法形式 : select a.column,b.column from 表a 连接类型 JOIN 表b on 连接条件
交叉连接 (CROSS JOIN) : 可理解为92语法中的笛卡尔积
select * from emp cross join dept;
自然连接 (NATURAL JOIN):根据两张表中相同字段名称,进行等值连接
select * from emp natural join dept;
内连接 (INNER JOIN)(INNER关键字可以省略)
–(1)等值连接
select e.ename, d.dname from emp e INNER JOIN dept d on e.deptno = d.deptno where e.sal > 2000
–(2)非等值连接
select e.ename, s.grade
from emp e
INNER JOIN salgrade s
on e.sal between s.losal and s.hisal
–(3)自连接
select e1.ename || '的上司是' || e2.ename
from emp e1
INNER JOIN emp e2
on e1.mgr = e2.empno
外连接 (OUTER关键字可以省略)
–(1)LEFR OUTER JOIN(左外连接)
select * from emp e LEFT OUTER JOIN dept d on e.deptno = d.deptno
–(2)RIGHT OUTER JOIN(右外连接)
select * from emp e RIGHT OUTER JOIN dept d on e.deptno = d.deptno
–(3)FULL OUTER JOIN(全外连接)
select * from emp e FULL OUTER JOIN dept d on e.deptno = d.deptno
接下来详细讲解各种连接
交叉连接
交叉联接是一种最简单的联接,交叉联接只实现一个笛卡尔积即可。这一步就是对两张表进行操作,把它们联接起来,生成两者的笛卡尔积。也就是将一个输入表的每行和另一张表的每行进行匹配。如果一张表有n行,另一张表有m行,将得到m * n行。
ANSI SQL-99:Cross Join
ANSI SQL-92:在两张表间放置一个逗号
内连接(ANSI SQL-99标准提出来的概念)
–内连接(整合了ANSI SQL-92的等值连接,不等值连接,自连接)
(1) --等值连接 --不等值连接 (2) --非自连接 --自连接
内连接要应用两个逻辑查询处理步骤:它首先像交叉联接一样,对两个输入表进行笛卡尔积运算:然后根据用户指定的谓词对结果进行过滤。和交叉联接一样,内联接也有两种标准语法。
ANSI SQL-99:Inner Join 或者 Join(由于内连接是默认的联接方式,所以也可以只写Join)
ANSI SQL-92:在两张表间放置一个逗号,在查询的where子句中写过滤条件。
强烈推荐使用Inner Join,因为假如你忘记写过滤条件(on),执行时SQL会报错。而如果使用SQL-92语法,则不会报错。那么这个内连接就变成交叉连接了! 而且实际开发中SQL语句会非常的复杂,写错的概率就很大了。
补充一下:
1.组合连接 有时候过滤条件不止一个,这时候就要用and来连接多个条件,这就叫做组合连接。例如:Table2表中定义了一个外键(col1和col2),引用了Table1表的col1和col2列,现在要写一个根据主外键关系来连接两个表的查询语句。该条件如下: from table1 as t1 join table2 as t2 on t1.col1 = t2.col1 and t1.col2 = t2.col2 2.多表连接 一个联接表运算符只对两个表进行操作,而一条查询语句可以包含多个联接。通常,当FROM子句中包含多个表运算符时,表运算符在逻辑上是按从左到右的顺序处理的。也就是说,第一个表运算符的结果将作为第二个表运算符的输入,第二个表运算符的结果将作为第三个运算符左边的输入,以此类推。
外连接
外连接会应用内连接所应用的两个逻辑处理步骤(笛卡尔积和On过滤),此外还多一个外连接特有的第三步:添加外部行。
ANSI SQL-92:在原有等值连接的基础上加上左边或者右边加上(+),实现外连接查询
ANSI SQL-99:
INNER JOIN(也可简写为JOIN): 如果表中有至少一个匹配,则返回行
LEFT JOIN: 即使右表中没有匹配,也从左表返回所有的行
RIGHT JOIN: 即使左表中没有匹配,也从右表返回所有的行
FULL JOIN: 只要其中一个表中存在匹配,就返回行
解释:在外连接中,要把一个表标记为“保留的”表,可以在表名之间使用关键字LEFT OUT JOIN、RIGHT OUTER JOIN ,以及 FULL OUTER JOIN,其中 OUTER 失键字是可选的。 LEFT关键字表示左边表的行是保留的关键字表示右边表的行是保留的,而FULL 关键字则表示左右两边表的行都是保留的。外联接的第三个逻辑杏询处理步骤就是要识别保留表中按照ON条件在另一个表找不到与之匹配的那些行,再把这些行添加到联接 的前两个步骤生成的结果表中:对于来自联接的非保留表的那些列,追加的外部行中的这些列则用NULL作为占位符。
补充一下:自然连接:
自然连接是在两张表中寻找那些数据类型和列名都相同的字段,然后自动地将他们连接起来,并返回所有符合条件按的结果。
自然连接无需指定连接列,sql会检查两个表中是否相同名称的列,且假设他们在连接条件中使用,并且在连接条件中仅包含一个连接列。不允许使用on语句,不允许指定显示列,显示列只能用*表示(oracle环境下测 试的)。对于每种连接类型(除了交叉连接外),均可指定natural。
最后用下面例子来总结一下知识点:
---多表联合查询 ---当需要获取的数据分布在多张表中使用多表联合查询 ---SQL92方式 ---笛卡尔积:将多个表的数据进行一一对应,所得到结果为多表的笛卡尔积. ---结果数量为所有表数量的乘积 seelct * from emp,dept; ---等值链接 ----先做表的笛卡尔积,然后筛选,筛选条件为等值筛选. ---查询员工的姓名,工作,薪资,部门名称 select * from emp,dept where dept.deptno=emp.deptno;---等值连接查询 ---可以直接在select子句中使用字段直接获取数据,但是效率低,建议字段前加上表名 ---注意:如果是公共字段必须声明表名 select * from emp e,dept d where d.deptno=e.deptno; ---不等值链接 ----查询员工的姓名,工作,工资,工资等级 select * from emp e,salgrade s where e.sal>=s.losal and e.sal<= s.hisal; ---自连接 ----相当于自己和自己做笛卡尔积 ----查询员工姓名,工作,薪资,以及上级领导姓名 select e1.ename,e1.job,e1.sal,e2.ename from emp e1,emp e2 where e1.mgr=e2.empno; ---外链接 ----左外链接 ---查询员工姓名,工作,薪资,部门名称以及没有部门的员工信息 select * from emp e,dept d where e.deptno=d.deptno(+); ----右外链接 ---查询员工姓名,工作,薪资,部门名称以及没有员工的部门 select * from emp e,dept d where e.deptno(+)=d.deptno;
----SQL99多表查询 ----注意1:依然可以给表添加别名 ----注意2;如果使用on或则usering关键字必须对结果进行筛选,必须使用inner join关键字组员于表与表的连接,其中inner可以省去 ----注意3:外连接的outer关键字可以不写 ----注意4:依然可以使用排序等关键字 ----1.笛卡尔积:使用cross join关键字 -----select 内容 from 表名 cross join -----查询员工及其部门 select * from emp cross join dept; ----2.筛选 -----自然连接:使用关键字natrual join ----使用:select 内容 from 表名 natural join 表名 select* from emp natural join dept; ---特点1:底层是笛卡尔积,按照同名同值字段自动进行等值筛选 ---缺点1:如果想按照字段名不同,但是字段值不同筛选怎么办? ----缺点2:如果只想按照部分字段结果筛选怎么办? ----解决1:使用using关键字 --作用1:指明使用指定的字段对联合查询的结果进行等值筛选 --注意:指明的字段必须是两边同名同值字段 --使用:select 内容 from 表名 inner join 表名 using(字段名) select * from emp inner join dept using(deptno,ename);--底层相当于先做了一个笛卡尔积,再进行等值筛选 ------解决2:使用on关键字,进行自定义链接查询 ----注意:普通筛选使用where筛选不使用on 好处:便于阅读 ----使用:select 内容 from 表名 inner join 表名 on 连接条件 where 普通筛选条件 select * from emp inner join dept on emp.deptno=dept.deptno where job='SALESMAN'; ------内连接 ---1.等值链接 ----先做表的笛卡尔积,然后筛选,筛选条件为等值筛选. ---查询员工的姓名,工作,薪资,部门名称 select * from emp inner join dept on dept.deptno=emp.deptno;---等值连接查询 ---可以直接在select子句中使用字段直接获取数据,但是效率低,建议字段前加上表名 ---注意:如果是公共字段必须声明表名 select * from emp e inner join dept d on d.deptno=e.deptno; ---2.不等值链接 ----查询员工的姓名,工作,工资,工资等级 select * from emp e,salgrade s where e.sal>=s.losal and e.sal<= s.hisal; ---3.自连接 -----查询员工姓名,工作,薪资,以及上级领导姓名 select e1.*,e2.ename from emp e1 inner join emp e2 on e1.mgr=e2.empno; ------外连接 ----左外连接:select 内容 from 表名 left outer join 表名 on 筛选条件 ---查询员工姓名,工作,薪资,部门名称以及没有部门的员工信息 select * from emp e left outer join dept d on d.deptno=e.deptno; ----右外连接:select 内容 from 表名 right outer join 表名 on 筛选条件 ---查询员工姓名,工作,薪资,部门名称以及没有员工的部门 select * from emp e right outer join dept d on d.deptno=e.deptno; ----全外连接:select 内容 from 表名 fill outer join 表名 on 筛选条件 select * from emp e full outer join dept d on d.deptno=e.deptno;
参考文章:
1. https://blog.csdn.net/weixin_43465312/article/details/103094430
2.https://blog.csdn.net/weixin_39722922/article/details/85113692
3. https://blog.csdn.net/weixin_44771312/article/details/98991622
4. https://blog.csdn.net/iteye_5198/article/details/82649372 (Oracle使用Scott用户登录)
5. https://blog.csdn.net/Lirx_Tech/article/details/51111662
6. https://www.toutiao.com/a6761205751114367495?wid=1618136606974