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

  • 相关阅读:
    HTML5实现音频播放
    百度编辑器UEditor常用设置函数大全
    .Net一般处理程序来实现用户名的验证
    软件设计师13-数据库设计
    软件设计师12-数据流图
    百度云BCC安装WordPress镜像
    Java获取客户端真实IP地址
    软件设计师11-面向对象技术
    百度云BCC主机宝镜像
    软件设计师10-系统开发模型
  • 原文地址:https://www.cnblogs.com/HarryVan/p/14543156.html
Copyright © 2011-2022 走看看