zoukankan      html  css  js  c++  java
  • 数据库-SQL多表查询(SQL 92 与SQL 99详解)

    一、概述:

    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

  • 相关阅读:
    BZOJ2219数论之神——BSGS+中国剩余定理+原根与指标+欧拉定理+exgcd
    Luogu 3690 Link Cut Tree
    CF1009F Dominant Indices
    CF600E Lomsat gelral
    bzoj 4303 数列
    CF1114F Please, another Queries on Array?
    CF1114B Yet Another Array Partitioning Task
    bzoj 1858 序列操作
    bzoj 4852 炸弹攻击
    bzoj 3564 信号增幅仪
  • 原文地址:https://www.cnblogs.com/HarryVan/p/14543156.html
Copyright © 2011-2022 走看看