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

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

oracle之复杂查询之一:多表连接技术的更多相关文章

  1. Oracle使用游标查询所有数据表备注

    功能作用:应用对应的SQL语句,能方便快速的查询Oracle数据库指定用户的所有用户表说明,快速知道每个数据表是做什么的,方便写文档和方案. 运行环境:搭建好Oracle数据库,并使用PQ/SQL D ...

  2. 010.简单查询、分组统计查询、多表连接查询(sql实例)

    -------------------------------------day3------------ --添加多行数据:------INSERT [INTO] 表名 [(列的列表)] --SEL ...

  3. Oracle使用游标查询指定数据表的所有字段名称组合而成的字符串

    应用场合:参考网上查询数据表的所有字段名代码,使用游标生成指定单个表的所有字段名跟逗号组成的用于select  逗号隔开的字段名列表 from字符串等场合. 查询结果输出如下: 当前数据表TB_UD_ ...

  4. Oracle和MSSQL查询有多少张表

    Oracle: SELECT count(*) FROM user_tables MSSQL: ) FROM sysobjects WHERE xtype='U' 这种方法可能会把dbo.dtprop ...

  5. Oracle之分组函数嵌套以及表连接

    --1 数据环境准备 scott 用户下面的emp,dept表 --2 要求 :求平均工资最高的部门编号,部门名称,部门平均工资 select d.deptno,d.dname,e.salfrom(s ...

  6. Oracle 执行计划(三)-------表连接方式

    SQL FOR TESTING: create table qcb_student_test( student_id number, student_name varchar2(20), studen ...

  7. MySQL开发——【联合查询、多表连接、子查询】

    联合查询 所谓的联合查询就是将满足条件的结果进行拼接在同一张表中. 基本语法: select */字段 from 数据表1 union [all | distinct] select */字段 fro ...

  8. 5月10日 python学习总结 单表查询 和 多表连接查询

    一. 单表查询  一 语法 select distinct 查询字段1,查询字段2,... from 表名 where 分组之前的过滤条件 group by 分组依据 having 分组之后的过滤条件 ...

  9. 一条sql,有分页,表合并查询,多表连接,用于oracle数据库

    SELECT * FROM ( SELECT TT.*,ROWNUM RN FROM ( SELECT A.CASE_ID AS TREATID, A.TYPE AS TYPE, B.CONTENT ...

随机推荐

  1. 代码优化与sql优化---未完待续

    万丈高楼平地起,还是得打一个好地基呀 减少对变量对重复计算 //一般这么写 for (int i = ; i < list.size(); i++) {...} //建议修改为: for (in ...

  2. 关于Dapper实现读写分离的个人思考

    概念相关     为了确保多线上环境数据库的稳定性和可用性,大部分情况下都使用了双机热备的技术.一般是一个主库+一个从库或者多个从库的结构,从库的数据来自于主库的同步.在此基础上我们可以通过数据库反向 ...

  3. MySQL服务操作

    启动: systemctl start mysqld.service; 状态: systemctl status mysqld.service; 重启: systemctl restart mysql ...

  4. 【Spring注解驱动开发】自定义组件如何注入Spring底层的组件?看了这篇我才真正理解了原理!!

    写在前面 最近,很多小伙伴出去面试都被问到了Spring问题,关于Spring,细节点很多,面试官也非常喜欢问一些很细节的技术点.所以,在 Spring 专题中,我们尽量把Spring的每个技术细节说 ...

  5. C++类和对象的封装 点和圆的案例

    主要练习 :在类中可以让另一个类作为本类的成员. 案例:判断点和圆的位置关系. 一.第一种直接方法 using namespace std; #include <iostream> cla ...

  6. golang复杂数据结构

    1.数组 数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成.因为数组的长度是固定的,因此在Go语言中很少直接使用数组. 数组的每个元素可以通过索引下标来访问,索引下标的范 ...

  7. Docker系列——Docker安装&基础命令

    Docker 概述 Docker 是一个开源的应用容器引擎,Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化. ...

  8. 用python实现实时监控网卡流量

    很多时候,我们是需要查看服务器的网卡当前跑了多大流量,但对于网卡流量的查询,在linux下似乎没有像top那样的原生命令.虽然top功能很强大,可以实时查看cpu.内存.进程的动态,但是却没有对网卡流 ...

  9. mr原理简单分析

    背景 又是一个周末一天一天的过的好快,今天的任务干啥呢,索引总结一些mr吧,因为前两天有面试问过我?我当时也是简单说了一下,毕竟现在写mr程序的应该很少很少了,废话不说了,结合官网和自己理解写起. 官 ...

  10. 区块链入门到实战(31)之Solidity – 第一个程序

    为简单起见,我们使用在线Solidity开发工具Remix IDE编译和运行Solidity程序. 第1步 – 在File explorers选项卡下,新建一个test1.sol文件,代码如下: 示例 ...