zoukankan      html  css  js  c++  java
  • oracle之复杂查询之一:多表连接技术

    复杂查询之一:多表连接技术

    7.1 简单查询的解析方法:

    全表扫描:指针从第一条记录开始,依次逐行处理,直到最后一条记录结束;

    横向选择+纵向投影=结果集

    7.2 多表连接

    交叉连接(笛卡尔积)
    非等值连接
    等值连接 (内连)
    外连接  (内连的扩展,左外,右外,全连接)
    自连接   
    自然连接(内连,隐含连接条件,自动匹配连接字段)
    复合连接 (多个结果集进行并、交、差)

    范例:
    create table a (id int, name char(10));
    create table b (id int, loc char(10));

    insert into a values (1,'a');
    insert into a values (2,'b');
    insert into a values (2,'c');
    insert into a values (4,'d');

    insert into b values (1,'A');

    insert into b values (2,'B');
    insert into b values (3,'C');
    commit;

    SQL> select * from a;

            ID NAME
    ---------- ----------
             1 a
             2 b
             2 c
             4 d

    SQL> select * from b;

            ID LOC
    ---------- ----------
             1 A
             2 B
             3 C

    7.2.1 交叉连接(笛卡尔积)
    连接条件无效或被省略,两个表的所有行都发生连接,所有行的组合都会返回(n*m)

    SQL99写法:
    SQL> select * from a cross join b;

    oracle写法:
    SQL> select * from a,b;

            ID NAME               ID LOC
    ---------- ---------- ---------- ----------
             1 a                   1 A
             2 b                   1 A
             2 c                   1 A
             4 d                   1 A
             1 a                   2 B
             2 b                   2 B
             2 c                   2 B
             4 d                   2 B
             1 a                   3 C
             2 b                   3 C
             2 c                   3 C
             4 d                   3 C

    已选择12行。
       

    非等值连接:(连接条件非等值,也属于内连范畴)

    SQL99写法:
    SQL> select empno,ename,sal,grade,losal,hisal from emp join salgrade on sal between losal and hisal;

    oracle写法:
    SQL> select empno,ename,sal,grade,losal,hisal from emp,salgrade where sal between losal and hisal;

         EMPNO ENAME             SAL      GRADE      LOSAL      HISAL
    ---------- ---------- ---------- ---------- ---------- ----------
          7369 SMITH             800          1        700       1200
          7900 JAMES             950          1        700       1200
          7876 ADAMS           1100        1        700       1200
          7521 WARD             1250        2       1201       1400
          7654 MARTIN          1250        2       1201       1400
          7934 MILLER           1300         2       1201       1400
          7844 TURNER           1500       3       1401       2000
          7499 ALLEN            1600         3       1401       2000
          7782 CLARK            2450         4       2001       3000
          7698 BLAKE            2850         4       2001       3000
          7566 JONES            2975         4       2001       3000
          7788 SCOTT            3000         4       2001       3000
          7902 FORD             3000         4       2001       3000
          7839 KING             5000          5       3001       9999


    7.2.2 等值连接,典型的内连接

    SQL99写法:
    SQL> select * from a inner join b on a.id=b.id;

    oracle写法:
    SQL> select * from a,b where a.id=b.id;

            ID NAME               ID LOC
    ---------- ---------- ---------- ----------
             1 a                   1 A
             2 b                   2 B
             2 c                   2 B

    7.2.3 外连接包括左外连接,右外连接,全外连接

    1)左外连接

    SQL99语法:
    SQL> select * from a left join b on a.id=b.id;

    oracle语法:
    SQL> select * from a,b where a.id=b.id(+);

    结果:

             ID NAME               ID LOC
    ---------- ---------- ---------- ----------
             1     a                   1 A
             2     c                   2 B
             2     b                   2 B
             4     d

    2)右外连接

    SQL99语法:
    SQL>select * from a right join b on a.id=b.id;

    oracle语法:
    SQL> select * from a,b where a.id(+)=b.id;

    结果

            ID NAME               ID LOC
    ---------- ---------- ---------- ----------
             1 a                   1 A
             2 b                   2 B
             2 c                   2 B
                                       3 C

    3)全外连接

    SQL99语法:
    SQL> select * from a full join b on a.id=b.id;

            ID NAME               ID LOC
    ---------- ---------- ---------- ----------
             1 a                   1 A
             2 b                   2 B
             2 c                   2 B
             4 d
                                    3 C

    oracle语法:
    SQL> select * from a,b where a.id=b.id(+)
         union
         select * from a,b where a.id(+)=b.id;

            ID NAME               ID LOC
    ---------- ---------- ---------- ----------
             1 a                   1 A
             2 b                   2 B
             2 c                   2 B
             4 d
                                    3 C

    7.2.4 自连接

    sql99语法:
    SQL> select * from a a1 cross join a a2;

    oracle语法:
    SQL> select * from a a1,a a2;

    7.2.5 自然连接(属于内连中等值连接)
         
    在oralce中使用natural join,也就是自然连接。

    先看自然连接:

    SQL> select * from a natural join b;

            ID NAME       LOC
    ---------- ---------- ----------
             1 a          A
             2 b          B
             2 c          B

    -----将两个表分别再加一个列ABC后,则有两个公共列(ID列和ABC列),添加数据后,再尝试自然连接如何匹配。

    SQL> select * from a;

            ID NAME       ABC
    ---------- ---------- ----------
             1 a          s
             2 b          t
             2 c          u
             4 d          v

    SQL> select * from b;

            ID LOC        ABC
    ---------- ---------- ----------
             1 A          w
             2 B          t
             3 C          r

    SQL> select * from a natural join b;

            ID ABC        NAME       LOC
    ---------- ---------- ---------- ----------
             2 t          b          B

    在自然连接中可以使用using关键字:

    当使用natraul join关键字时,如果两张表中有多个字段,它们具有相同的名称和数据类型,那么这些字段都将被oracle自作主张的将他们连接起来。但如果名称相同,类型不同,或者当你需要在多个字段同时满足连接条件的情况下,想人为指定某个(些)字段做连接,那么可以使用using 关键字。

    在oracle连接(join)中使用using关键字

    SQL> select id,a.abc,name,loc from a join b using(id);

            ID ABC        NAME       LOC
    ---------- ---------- ---------- ----------
             1 s          a          A
             2 t          b          B
             2 u          c          B

    using里未必只能有一列

    SQL> select id,abc,name,loc from a join b using(id,abc);

            ID ABC        NAME       LOC
    ---------- ---------- ---------- ----------
             2 t              b          B

    总结:

    1、使用using关键字时,如果select的结果列表项中包含了using关键字所指明的那个关键字,那么,不要指明该关键字属于哪个表(考点)。
    2、using中可以指定多个列名。
    3、natural和using关键字是互斥的,也就是说不能同时出现。

    在实际工作中看,内连接,左外连接,以及自然连接用的较多,而且两表连接时一般是多对一的情况居多,即a表行多,b表行少, 从连接字段来看,b表为父表,其连接字段做主键, a表为子表,其连接字段为外键。

    典型的就是dept表和emp表的关系,两表连接字段是deptno,建有主外键关系。

    这与数据库设计要求符合第三范式有关。


    7.3 复合查询(使用集合运算符)

    Union,对两个结果集进行并集操作,重复行只取一次,同时进行默认规则的排序;

    Union All,对两个结果集进行并集操作,包括所有重复行,不进行排序;

    Intersect,对两个结果集进行交集操作,重复行只取一次,同时进行默认规则的排序;

    Minus,对两个结果集进行差操作,不取重复行,同时进行默认规则的排序。

    复合查询操作有 并,交,差 3种运算。

    举例:

    SQL> create table dept1 as select * from dept where rownum <=1;

    SQL> insert into dept1 values (80, 'MARKTING', 'BEIJING');
    SQL> select * from dept;

        DEPTNO DNAME          LOC
    ---------- -------------- -------------
            10 ACCOUNTING     NEW YORK
            20 RESEARCH          DALLAS
            30 SALES                 CHICAGO
            40 OPERATIONS     BOSTON


    SQL> select * from dept1;

        DEPTNO DNAME          LOC
    ---------- -------------- -------------
            10 ACCOUNTING     NEW YORK
            80 MARKTING         BEIJING

    7.3.1 union

    SQL>
    select * from dept
    union
    select * from dept1;

        DEPTNO DNAME          LOC
    ---------- -------------- -------------
            10 ACCOUNTING     NEW YORK
            20 RESEARCH         DALLAS
            30 SALES                CHICAGO
            40 OPERATIONS     BOSTON
            80 MARKTING       BEIJING


    7.3.2 union all

    SQL>
    select * from dept
    union all
    select * from dept1;

        DEPTNO DNAME          LOC
    ---------- -------------- -------------
            10 ACCOUNTING     NEW YORK
            20 RESEARCH           DALLAS
            30 SALES                  CHICAGO
            40 OPERATIONS      BOSTON
            10 ACCOUNTING     NEW YORK
            80 MARKTING         BEIJING

    特别注意:可以看出只有union all的结果集是不排序的。

    7.3.3 intersect

    SQL>
    select * from dept
    intersect
    select * from dept1;

        DEPTNO DNAME          LOC
    ---------- -------------- -------------
            10 ACCOUNTING     NEW YORK


    7.3.4 minus (注意谁minus谁)
    SQL>
    select * from dept
    minus
    select * from dept1;

        DEPTNO DNAME          LOC
    ---------- -------------- -------------
            20 RESEARCH          DALLAS
            30 SALES                 CHICAGO
            40 OPERATIONS     BOSTON


    SQL>
    select * from dept1
    minus
    select * from dept;

        DEPTNO DNAME          LOC
    ---------- -------------- -------------
            80 MARKTING       BEIJING

    7.4 复合查询中的几点注意事项

    1)列名不必相同,但要类型匹配且顺序要对应,大类型对上就行了,比如char对varchar2,date对timestamp都可以,字段数要等同,不等需要补全。

    create table a (id_a int,name_a char(10));
    create table b (id_b int,name_b char(10),sal number(10,2));

    insert into a values (1, 'sohu');
    insert into a values (2, 'sina');

    insert into b values (1, 'sohu', 1000);
    insert into b values (2, 'yahoo', 2000);
    commit;

    SQL> select * from a;

          ID_A NAME_A
    ---------- ----------
             1 sohu
             2 sina

    SQL> select * from b;

          ID_B NAME_B            SAL
    ---------- ---------- ----------
             1 sohu             1000
             2 yahoo            2000

    SQL>
    select id_a,name_a from a
    union
    select id_b,name_b from b;

          ID_A NAME_A
    ---------- ----------
             1 sohu
             2 sina
             2 yahoo

    2)四种集合运算符优先级按自然先后顺序,如有特殊要求可以使用()。

    3)关于复合查询中order by 使用别名排序的问题:

    a) 缺省情况下,复合查询后的结果集是按所有字段的组合进行排序的(除union all 外)

    如果不希望缺省的排序,也可以使用order by显示排序

    select id_a, name_a name from a
    union
    select id_b, name_b name from b
    order by name;

          ID_A NAME
    ---------- ----------
             2 sina
             1 sohu
             2 yahoo

    select id_a, name_a from a
    union
    select id_b, name_b from b
    order by 2;

          ID_A NAME_A
    ---------- ----------
             2 sina
             1 sohu
             2 yahoo

    b) 显式order by是参照第一个select语句的列元素。所以,order by后的列名只能是第一个select使用的列名、别名、列号(考点)。

    如果是补全的null值需要order by,则需要使用别名。

    SQL>
    select id_a, name_a name,to_number(null) from a
    union
    select id_b, name_b name,sal from b
    order by sal;

    ORA-00904: "SAL": 标识符无效


    SQL>
    select id_a, name_a name,to_number(null) from a
    union
    select id_b, name_b name,sal from b
    order by 3;


          ID_A NAME       TO_NUMBER(NULL)
    ---------- ---------- ---------------
             1 sohu                   1000
             2 yahoo                 2000
             1 sohu
             2 sina

    SQL>
    select id_b, name_b name,sal from b
    union
    select id_a, name_a name,to_number(null) from a
    order by sal;

          ID_B NAME              SAL
    ---------- ---------- ----------
             1 sohu              1000
             2 yahoo            2000
             1 sohu
             2 sina

    SQL>
    select id_a, name_a name,to_number(null) aa from a
    union
    select id_b, name_b name,sal aa from b
    order by aa;

          ID_A NAME               AA
    ---------- ---------- ----------
             1 sohu              1000
             2 yahoo            2000
             1 sohu
             2 sina

    c) 排序是对复合查询结果集的排序,不能分别对个别表排序,order by 只能一次且出现在最后一行;

    SQL>
    select id_a, name_a from a order by id_a
    union
    select id_b, name_b from b order by id_b;

    ORA-00933: SQL 命令未正确结束

  • 相关阅读:
    Atitit. visual studio vs2003 vs2005 vs2008  VS2010 vs2012 vs2015新特性 新功能.doc
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.跨语言反射api 兼容性提升与增强 java c#。Net  php  js
  • 原文地址:https://www.cnblogs.com/jinxf/p/9165880.html
Copyright © 2011-2022 走看看