Oracle查询优化改写_3

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yhzhaohy/article/details/81223625

对应的第三章”操作多个表“


1.UNION ALL与空字符串

UNION ALL 常常用来合并多个结果集。

select ename AS 名称 from emp where empno = 7788 
UNION ALL
select null AS 名称 from dual
UNION ALL 
select '' AS 名称 from dual;

得到的结果如下:

名称
SCOTT
null
null

可以看到,当一个数据集列不够时,可以用null来填充该列的值,而空字符串在Oracle中常常也相当于null;

为什么不说空字符串等于null呢?看下面的示例:

select sal AS 工资 from emp where empno = 7788
UNION ALL 
select '' AS 工资 from dual;

--报错:表达式必须具有与对应表达式相同的数据类型【sal类型:"NUMBER" ,''类型:"varchar2"】

可以看到,空字符串本身是 varchar2类型,这区别于null可以是任何类型,因此,它们是不等价的。

2.UNION和OR
UNION ALL和UNION的区别
1. UNION ALL合并结果集的时候,数据可能会重复。
2. UNION 合并结果集的时候,会对数据进行去重操作。

在使用UNION和OR时,要特别注意,防止由于去重导致查询结果错误。

SQL1:
select empno,deptno from emp where mgr = 7698 order by 1;

SQL2:
select empno,deptno from emp where job = 'SALESMAN' order by 1;

两个sql得到的结果如下:

SQL1:

empno deptno
7944 30
7521 30
7654 30
7844 30
7900 30

SQL2:

empno deptno
7944 30
7521 30
7654 30
7844 30

1)如果使用OR条件,查询结果将是5条

select deptno from emp where mgr = 7698 or job = 'SALESMAN' order by 1;
deptno
30
30
30
30
30

2)使用UNION来合并两个条件的查询结果集

select deptno from emp where mgr = 7698
UNION
select deptno from emp where job = 'SALESMAN';

得到的结果如下

deptno
30

在这种情况下,我们在使用UNION来去重合并结果集时,一定要在查询的时候,加一个可以唯一标识各行的列,例如 empno。

除了可以使用唯一列,主键外,也可以用rowid。

3.inner join/left join/right join/full join 区别
  1. 1)inner join:内连接,返回左右表中,相匹配的数据。
select l.str AS left_str,r.str AS right_str from left_table l 
    inner join right_table r on l.v = r.v;

--使用where条件
select l.str AS left_str,r.str AS right_str from left_table l ,right_table r 
    where l.v = r.v;
  1. 2)left join:左(外)连接,左表为主表,左表返回所有的数据,右表只返回与左表相匹配的数据。右表的字段,查询结果可能为空
select l.str AS left_str,r.str AS right_str from left_table l 
    left join right_table r on l.v = r.v;

--加(+)后的写法
select l.str AS left_str,r.str AS right_str from left_table l ,right_table r 
    where l.v = r.v(+);
  1. 3)right join:右(外)连接,右表为主表,右表返回所有的数据,左表只返回与右表相匹配的数据。左表的字段,查询结果可能为空
select l.str AS left_str,r.str AS right_str from left_table l 
    right join right_table r on l.v = r.v;

--加(+)后的写法
select l.str AS left_str,r.str AS right_str from left_table l ,right_table r 
    where l.v(+) = r.v;
  1. 4)full join:完全连接,返回左表和右表中的全部数据,左右表相匹配的数据在同一行,非匹配的数据,只显示左表或右表的数据。左表,右表的字段,查询结果都可能为空,但不同时为空。
select l.str AS left_str,r.str AS right_str from left_table l 
    full join right_table r on l.v = r.v;

--full join 没有(+)的写法
4.外连接中,条件不要乱放
select l.str AS left_str,r.str AS right_str,r.status from left_table l 
left join right_table r on l.v = r.v order by 1, 2;
left_str right_str status
left_1
left_2
left_3 right_3 1
left_4 right_4 0

此时,只想要right_table表显示 status=1的部分数据,即要求显示结果如下所示:

left_str right_str status
left_1
left_2
left_3 right_3 1
left_4

4.1)修改sql如下:

left join 用法:
select l.str AS left_str,r.str AS right_str,r.status from left_table l 
left join right_table r on l.v = r.v where r.status = 1 order by 1,2;

(+)用法:
select l.str AS left_str,r.str AS right_str,r.status from left_table l, right_table r
where l.v = r.v(+) and r.status = 1 order by 1,2;

此时得到的结果如下:

left_str right_str status
left_3 right_3 1

查询结果错误。

4.2)正确的sql如下:

left join 用法:
select l.str AS left_str,r.str AS right_str,r.status from left_table l 
left join right_table r on l.v = r.v and r.status = 1 order by 1,2;

(+)用法:
select l.str AS left_str,r.str AS right_str,r.status from left_table l, right_table r
where l.v = r.v(+) and r.status(+) = 1 order by 1,2;

上述sql,也可以像下面这样写

select l.str AS left_str,r.str AS right_str,r.status from left_table l 
left join (select * from right_table where status = 1) r on l.v = r.v order by 1,2;
5.比较两张表中数据是否相同吗,以及相同数据的条数是否相同

5.1)比较两个表数据是否相同

    select 
        a.empno,a.empname,b.empno,b.empname 
    from 
        emp_a a full join emp_b b
    on 
        a.empno = b.empno 
    where 
        (a.empno IS NULl or b.empno IS NULL);

此时可以比较两张表中数据是否相同,但是无法比较两张表中相同数据的条数,是否相同。

5.2)表两张表中数据,以及相同数据的条数是否相同

    select 
        a.empno,a.empname,a.num,b.empno,b.empname,b.num 
    from 
        (select empno,empname,count(*) as num from emp_a group by empno,empname) a 
    full join 
        (select empno,empname,count(*) as num from emp_b group by empno,empname) b
    on 
        (a.empno = b.empno and a.num = b.num) 
    where 
        (a.empno IS NULl or b.empno IS NULL);
6.空值处理

6.1)如果null参与算术运算[+,-,*,],则该算术表达式的值为null。

6.2)如果null参与比较运算[:>=,<=,<>],则结果可视为false。要使用 IS NULL,IS NOT NULL

6.3)使用count(*),count(1),计数会包含NULL值和重复项;使用count(字段1),计数时不包含,字段1为null的数据。

6.4)Oracle中,如果子查询包含空值null,则 NOT IN(该子查询)返回结果为空。


select 12 as a from dual WHERE 1 IN (1,,NULL);

 A
---
12

select 12 as b from dual WHERE 1 NOT IN (2,3,,NULL);

 B
---
null

猜你喜欢

转载自blog.csdn.net/yhzhaohy/article/details/81223625