数据库基本功之复杂查询-多表连接

1. 简单查询的解析方法

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

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

2. 多表连接

交叉连接(笛卡尔积)
非等值连接
等值连接
内连
外连接(内连的扩展,左外,右外,全连接)
自连接
自然连接(内连,隐含连接条件,自动匹配连接字段)
集合运算 (多个结果集进行并、交、差)
SQL> -- 范例:
SQL> 
SQL> create table a1 (id int, name char (10));
create table b1 (id int, loc char (10));
insert into a1 values(1,'a');

Table created.

SQL> 
Table created.

SQL> insert into a1 values(2,'b');
insert into a1 values(2,'c');

1 row created.

SQL> 
1 row created.

SQL> 
1 row created.

SQL> insert into a1 values(4,'d');

1 row created.

SQL> insert into b1 values(1,'A');

1 row created.

SQL> insert into b1 values(2,'B');

1 row created.

SQL> insert into b1 values(3,'C');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from a1;

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

SQL> select * from b1;

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

SQL> 

2.1 交叉连接/cross join(笛卡尔积)

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

SQL> 
SQL> -- SQL99写法:
SQL> select * from a1 cross join b1;

        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 rows selected.

SQL> -- oracle写法:
SQL> select * from a1, b1;

        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 rows selected.

SQL> select * from a1 cross join b1;

        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 rows selected.

SQL> -- 非等值连接:(连接条件非等值,也属于内连范畴)
SQL> 
SQL> select * from salgrade;

     GRADE      LOSAL      HISAL
---------- ---------- ----------
         1        700       1200
         2       1201       1400
         3       1401       2000
         4       2001       3000
         5       3001       9999

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
      7876 ADAMS                                1100          1        700       1200
      7900 JAMES                                 950          1        700       1200
      7521 WARD                                 1250          2       1201       1400
      7654 MARTIN                               1250          2       1201       1400
      7934 MILLER                               1300          2       1201       1400
      7499 ALLEN                                1600          3       1401       2000
      7844 TURNER                               1500          3       1401       2000
      7566 JONES                                2975          4       2001       3000
      7698 BLAKE                                2850          4       2001       3000
      7782 CLARK                                2450          4       2001       3000
      7788 SCOTT                                3000          4       2001       3000
      7902 FORD                                 3000          4       2001       3000

13 rows selected.

SQL> 

2.2 内连接/inner join(等值连接)

SQL> -- SQL99写法:
SQL> 
SQL> select * from a1 inner join b1 on a1.id = b1.id;

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

SQL> -- oracle写法:
SQL> select * from a1,b1 where a1.id = b1.id;

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

SQL> 

2.3 外连接

在等值的数据基础上.也查询相应不等值的数据

2.3.1 左外连接/left join

SQL> 
SQL> -- SQL99语法:
SQL> select * from a1 left join b1 on a1.id = b1.id;

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

SQL> -- oracle语法:
SQL> 
SQL> select * from a1, b1 where a1.id = b1.id(+);

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

SQL> 

 2.3.2 右外连接/right join

 

SQL> 
SQL> -- SQL99语法:
SQL> select * from a1 right join b1 on a1.id = b1.id;

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

SQL> -- oracle语法:
SQL> select * from a1,b1 where a1.id(+)=b1.id;

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

SQL> 

2.3.3 全外连接/full join

SQL> -- oracle语法:
SQL> select * from a1,b1 where a1.id(+)=b1.id;

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

SQL> -- SQL99语法:
SQL> select * from a1 full join b1 on a1.id = b1.id;

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

SQL> select * from a1,b1 where a1.id = b1.id (+)
  2  union
  3  select * from a1,b1 where a1.id(+)=b1.id;

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

SQL> 

2.4 自连接/cross join

SQL> 
SQL> -- sql99语法:
SQL> 
SQL> select * from a1 cross join a1;
select * from a1 cross join a1
       *
ERROR at line 1:
ORA-00918: column ambiguously defined


SQL> -- oracle语法:
SQL> select * from a1 x, a1 y;

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

16 rows selected.

SQL> 

2.5 自然连接/natural join

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

自然连接实验:

2.5.1 无公共列数据查询

SQL> select * from a1 natural join b1;

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

SQL> 

2.5.2 添加公共列

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

SQL> select * from a1 natural join b1;

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

SQL> 
SQL> 
SQL> alter table a1 add abc char(2);

Table altered.

SQL> alter table b1 add abc char(2);

Table altered.

SQL> 
SQL> select * from a1 natural join b1;

no rows selected

SQL> 

2.5.3 新列插入数据

SQL> 
SQL> update a1 set abc='s' where name='a';

1 row updated.

SQL> update a1 set abc='t' where name='b';

1 row updated.

SQL> update a1 set abc='u' where name='c';

1 row updated.

SQL> update a1 set abc='v' where name='d';

1 row updated.

SQL> update b1 set abc='w' where loc='A';

1 row updated.

SQL> update b1 set abc='t' where loc='B';

1 row updated.

SQL> update b1 set abc='r' where loc='C';

1 row updated.

SQL> select * from a1;

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

SQL> select * from b1;

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

SQL> 

2.5.4 查看自然连接如何匹配

SQL> 
SQL> select * from a1 natural join b1;

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

SQL> 

2.6 using关键字

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

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

2.6.1 Using未引用的公共列要指定表名

SQL> 
SQL> -- 此处的abc是公共列,要指定是a1表
SQL> select id,a1.abc, name, loc from a1 join b1 using(id);

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

SQL> -- 此处的abc是公共列,要指定是a1表
SQL> select id,abc, name, loc from a1 join b1 using(id);
select id,abc, name, loc from a1 join b1 using(id)
          *
ERROR at line 1:
ORA-00918: column ambiguously defined


SQL> select * from a1;

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

SQL> select * from b1;

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

SQL> 


2.6.2 using引用的列名不可指定表

SQL> 
SQL> -- using引用的列名不可指定表
SQL> select id,a1.abc, name, loc from a1 join b1 using(a1.id);
select id,a1.abc, name, loc from a1 join b1 using(a1.id)
                                                    *
ERROR at line 1:
ORA-01748: only simple column names allowed here


SQL> 


2.6.3 using可指定多列

SQL> 
SQL> select id,abc,name,loc from a1 join b1 using(id,abc);

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

SQL> -- select的公共列无需在using中指定表(using子句的列部分不能有限定词)
SQL> select id,a1.abc,name,loc from a1 join b1 using(id,abc);
select id,a1.abc,name,loc from a1 join b1 using(id,abc)
          *
ERROR at line 1:
ORA-25154: column part of USING clause cannot have qualifier


SQL> select * from a1 join b1 using(id);

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

SQL> 

2.6.4 natural和using关键字不可同时出现

SQL> 
SQL> -- natural和using关键字是互斥的
SQL> select * from a1 natural join b1 using(id);
select * from a1 natural join b1 using(id)
                                 *
ERROR at line 1:
ORA-00933: SQL command not properly ended


SQL> 

2.6.5 总结:

1、使用using关键字时,如果select的结果列表项中包含了using关键字所指明的那个关键字,那么,不要指明该关键字属于哪个表(知识点).

2、using中可以指定多个列名.
3、natural和using关键字是互斥的,也就是说不能同时出现.

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

典型的就是dept表和emp表的关系,两表连接字段是deptno,键有主、外键关系
这与数据库设计要求符合第三范式有关.

SQL> 
SQL> select * from emp;        -- deptno外键

     EMPNO ENAME                          JOB                                MGR HIREDATE               SAL       COMM     DEPTNO
---------- ------------------------------ --------------------------- ---------- --------------- ---------- ---------- ----------
      7369 SMITH                          CLERK                             7902 17-DEC-80              800                    20
      7499 ALLEN                          SALESMAN                          7698 20-FEB-81             1600        300         30
      7521 WARD                           SALESMAN                          7698 22-FEB-81             1250        500         30
      7566 JONES                          MANAGER                           7839 02-APR-81             2975                    20
      7654 MARTIN                         SALESMAN                          7698 28-SEP-81             1250       1400         30
      7698 BLAKE                          MANAGER                           7839 01-MAY-81             2850                    30
      7782 CLARK                          MANAGER                           7839 09-JUN-81             2450                    10
      7788 SCOTT                          ANALYST                           7566 24-JAN-87             3000                    20
      7844 TURNER                         SALESMAN                          7698 08-SEP-81             1500          0         30
      7876 ADAMS                          CLERK                             7788 02-APR-87             1100                    20
      7900 JAMES                          CLERK                             7698 03-DEC-81              950                    30
      7902 FORD                           ANALYST                           7566 03-DEC-81             3000                    20
      7934 MILLER                         CLERK                             7782 23-JAN-82             1300                    10

13 rows selected.

SQL> select * from dept;              -- deptno主键

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

SQL> 

3. 集合运算

Union ,对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序;
Union All ,对两个结果集进行并集操作,包括所有重复行,不进行排序;
Intersect ,对两个结果集进行交集操作,不包括重复行、列名不必相同、但列的数量和数据类型必相同,同时进行默认规则的排序;
Minus ,对两个结果集进行差操作,不包括重复行,同时进行默认规则的排序. 集合操作有 并,交,差3种运算.

SQL> 
SQL> -- 举例:
SQL> -- 新建一个表
SQL> 
SQL> create table dept1 as select * from dept where rownum <=1;

Table created.

SQL> insert into dept1 values(80,'MARKTING','BEIJING');

1 row created.

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

SQL> 

3.1 union

对两个结果集进行并集操作,不包括重复行,同时进行默认规则的排序

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

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

SQL> 

3.2 union all

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

SQL> 
SQL> select * from dept
  2  union all
  3  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

6 rows selected.

SQL> 

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

3.3 intersect

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

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

SQL> 


3.4 minus

(注意谁minus谁)

SQL> 
SQL> select * from dept
  2  minus
  3  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

SQL> 

4. 集合运算中注意事项

4.1 列名不必相同,但大类型要匹配且顺序要对应

比如char 对varchar2,date对timestamp都可以,字段数要等同,不等需要补全.

SQL> 
SQL> create table x (id_x int, name_x char (10));

Table created.

SQL> create table y (id_y int, name_y char (10), sal number (10,2));

Table created.

SQL> insert into x values (1, 'sohu');

1 row created.

SQL> insert into x values (1, 'sina');

1 row created.

SQL> insert into y values (1, 'sohu', 1000);

1 row created.

SQL> insert into y values (2, 'google', 2000);

1 row created.

SQL> commit;

Commit complete.

SQL> select * from x;

      ID_X NAME_X
---------- ------------------------------
         1 sohu
         1 sina

SQL> select * from y;

      ID_Y NAME_Y                                SAL
---------- ------------------------------ ----------
         1 sohu                                 1000
         2 google                               2000

SQL> select id_x, name_x from x
  2  union
  3  select id_y,name_y from y;

      ID_X NAME_X
---------- ------------------------------
         1 sina
         1 sohu
         2 google

SQL> 

4.2 多表可复合集合运算,四种运算符按自然先后顺序,特殊要求可以使用()

4.3 order by使用别名排序的问题

缺省情况下,集合运算后的结果集是按所有字段的组合进行排序的(除union all 外)
如果不希望缺省的排序,也可以使用order by显示排序

4.3.1 使用别名排序

SQL> 
SQL> -- 使用别名排序
SQL> select id_x,name_x name from x
  2  union
  3  select id_y,name_y name from y
  4  order by name;

      ID_X NAME
---------- ------------------------------
         2 google
         1 sina
         1 sohu

SQL> -- 参照第一个别名排序
SQL> 
SQL> select id_x,name_x name from x
  2  union
  3  select id_y,name_y from y
  4  order by name;

      ID_X NAME
---------- ------------------------------
         2 google
         1 sina
         1 sohu

SQL> 

4.3.2 使用列号排序

SQL> -- 参照第一个select列的位置编号
SQL> select id_x, name_x from x
  2  union
  3  select id_y, name_y from y
  4  order by 2;

      ID_X NAME_X
---------- ------------------------------
         2 google
         1 sina
         1 sohu

SQL> 

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

4.3.3 补全的null值排序,则要使用别名

SQL> 
SQL> select id_x, name_x name, to_number(null) from x
  2  union
  3  select id_y,name_y name , sal from y
  4  order by sal;
order by sal
         *
ERROR at line 4:
ORA-00904: "SAL": invalid identifier


SQL> 

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

4.3.3.1 解决办法1:根据列号排序

SQL> select id_x, name_x name, to_number(null) from x
  2  union
  3  select id_y,name_y name , sal from y
  4  order by sal;
order by sal
         *
ERROR at line 4:
ORA-00904: "SAL": invalid identifier


SQL> select id_x, name_x name, to_number(null) from x
  2  union
  3  select id_y,name_y name , sal from y
  4  order by 3;

      ID_X NAME                           TO_NUMBER(NULL)
---------- ------------------------------ ---------------
         1 sohu                                      1000
         2 google                                    2000
         1 sina
         1 sohu

SQL> 
SQL> 

4.3.3.2 解决办法2:将第二个select放在前面

SQL> 
SQL> select id_y,name_y name , sal from y
  2  union
  3  select id_x, name_x name, to_number(null) from x
  4  order by sal;

      ID_Y NAME                                  SAL
---------- ------------------------------ ----------
         1 sohu                                 1000
         2 google                               2000
         1 sina
         1 sohu

SQL> 

4.3.3.3 解决办法3:按照别名排序

SQL> select id_x, name_x name, to_number(null) aa from x
  2  union
  3  select id_y,name_y name , sal aa from y
  4  order by aa;

      ID_X NAME                                   AA
---------- ------------------------------ ----------
         1 sohu                                 1000
         2 google                               2000
         1 sina
         1 sohu

SQL> 

4.3.4 不能分别对个别表排序

排序是对结果集的排序(包括复合集合运算),不能分别对个别表排序,order by 只能出现一次且在最后一行;

SQL> 
SQL> select id_x, name_x from x order by id_x
  2  union
  3  select id_y,name_y from y order by id_y;
union
*
ERROR at line 2:
ORA-00933: SQL command not properly ended


SQL> 

-- ORA-00933: SQL 命令未正确结束
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值