• 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 命令未正确结束

  • 相关阅读:
    适配器
    策略
    oom的各种情况
    sql 优化//TODO
    聚簇索引和非聚簇索引
    Shard内部原理
    es集群健康状态
    转载 R语言颜色基础设置
    三维数据的展示
    python 文件保存 出错
  • 原文地址:https://www.cnblogs.com/jinxf/p/9165880.html
Copyright © 2020-2023  润新知