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

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. vue 三元表达式当出现elif

    方式一: <span class="person_name">{{item.type_name == '车商' ? item.title : item.type_nam ...

  2. 第一次使用Git Bash Here 将本地代码上传到码云

    当我们安装成功git工具时候,初次使用Git时,需要Git进行配置. 1.点击桌面上的这个图标,打开Git Bash:如图所示 2.配置自己的用户名和邮箱 git config --global us ...

  3. python设计模式之解释器模式

    python设计模式之解释器模式 对每个应用来说,至少有以下两种不同的用户分类. [ ] 基本用户:这类用户只希望能够凭直觉使用应用.他们不喜欢花太多时间配置或学习应用的内部.对他们来说,基本的用法就 ...

  4. 教你如何使用ES6的Promise对象

    教你如何使用ES6的Promise对象 Promise对象,ES6新增的一个全新特性,这个是 ES6中非常重要的一个对象 Promise的设计初衷 首先,我们先一起了解一下,为什么要设计出这么一个玩意 ...

  5. 学长小清新题表之UOJ 14.DZY Loves Graph

    学长小清新题表之UOJ 14.DZY Loves Graph 题目描述 \(DZY\)开始有 \(n\) 个点,现在他对这 \(n\) 个点进行了 \(m\) 次操作,对于第 \(i\) 个操作(从 ...

  6. 【WC2013】 糖果公园 - 树上莫队

    问题描述 Candyland 有一座糖果公园,公园里不仅有美丽的风景.好玩的游乐项目,还有许多免费糖果的发放点,这引来了许多贪吃的小朋友来糖果公园游玩.糖果公园的结构十分奇特,它由 n 个游览点构成, ...

  7. Centos7第一安装后无法联网

  8. fatal error: glib.h: No such file or directory

    在学习BLE bluez的时候,做了一个测试程序,看到gatttool.c下面有一个glib解析命令行的功能,想移植到自己的程序接口中,但是添加了#include <glib.h>后,出现 ...

  9. JDBC驱动程序分类

    JDBC驱动程序分类 JDBC驱动程序:各个数据库厂商根据JDBC的规范制作的 JDBC 实现类的类库 JDBC驱动程序总共有四种类型: 第一类:JDBC-ODBC桥. 第二类:部分本地API部分Ja ...

  10. 第4章 SparkSQL数据源

    第4章 SparkSQL数据源 4.1 通用加载/保存方法 4.1.1 手动指定选项 Spark SQL的DataFrame接口支持多种数据源的操作.一个DataFrame可以进行RDDs方式的操作, ...