Oracle查询优化改写技巧与案例总结一

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

一、简介

本文将总结一些Oracle查询优化方法与改写技巧,通过一些案例说明用法,本文为观看《Oracle查询优化改写技巧与案例》一书观后的一些总结,大家有空的话可以去阅读一下,下面直接分点总结一些比较有用的优化技巧。

二、优化技巧

【1】. 判空处理使用is null / is not null,不能使用 = null进行判断

查询结果如上图,yxlx这个字段为空,如果使用 = null判断的话,查询结果不正确。

select t.* from zhxg_yx_yxxcgl_cssz t where t.yxlx = null;

必须使用is null / is not null进行判空处理:

select t.* from zhxg_yx_yxxcgl_cssz t where t.yxlx is null;

【2】.  巧用greatest()/least()/coalesce()函数

greatest():  返回列表中最大的值,列表中的数据类型必须一致.

least(): 返回列表中最小的值,列表中的数据类型必须一致.

coalesce(): 返回列表中第一个非空的值,列表汇中的数据必须同一类型或者能转换成同一类型,效果类似nvl()/case when表达式.

--greatest 返回值列表中最大值
select greatest('A', 'B', 'C') from dual; -- 返回C
select greatest(null, 'B', 'C') from dual; -- 返回null

--least 返回值列表中最小值
select least('A', 'B', 'C') from dual; -- 返回A
select least(null, 'B', 'C') from dual; -- 返回null

--coalesce 返回该表达式列表的第一个非空value
select coalesce(1, null, 2) from dual; -- 返回1
select coalesce(null, 2, 1) from dual; -- 返回2


select coalesce(t.empno, t.mgr) as col from scott.emp t; 
--等价于
select nvl(t.empno, t.mgr) as col from scott.emp t; 
--等价于
select case when t.empno is not null then t.empno when t.mgr is not null then t.mgr end as col from scott.emp t; 

【3】. 查询语句尽量使用别名,易于读懂分析sql语句

select t.zhlx as 账号类型, t.xxjd as 经度, t.xxwd as 纬度
  from ZHXG_YX_YXXCGL_CSSZ t;

--实际项目中,通常都是用简名取别名
select t.zhlx as lx, t.xxjd as jd, t.xxwd as wd from ZHXG_YX_YXXCGL_CSSZ t

--在where子句中使用别名,注意要多嵌套一层
select r.*
  from (select t.zhlx as lx, t.xxjd as jd, t.xxwd as wd
          from ZHXG_YX_YXXCGL_CSSZ t) r
 where r.lx is not null

【4】. select子句中巧用条件判断逻辑

这里主要通过case when子句或者nvl(),nvl2(),decode()函数来实现:

--性别码
select t.xbm as xbm
  from ZHXG_YX_YXXCGL_XSJBXX t
 where t.pkid = '07cc1b86-9df9-4b2e-9942-d14c7f238f89';

--使用case..when 
select t.xbm,
       case
         when t.xbm = '1' then
          '男'
         when t.xbm = '2' then
          '女'
         else
          '保密'
       end as sex
  from ZHXG_YX_YXXCGL_XSJBXX t
 where t.pkid = '07cc1b86-9df9-4b2e-9942-d14c7f238f89';

--使用decode
select t.xbm, decode(t.xbm, '1', '男', '2', '女', '保密') as sex
  from ZHXG_YX_YXXCGL_XSJBXX t
 where t.pkid = '07cc1b86-9df9-4b2e-9942-d14c7f238f89';

【5】. 限制返回记录的行数

--rownum是一个伪列
select rownum, t.pkid, t.xh, t.lqh
  from zhxg_yx_yxxcgl_xsjbxx t
 where rownum <= 10;

获取rownum = 5这条记录,直接使用如下sql是查询不出结果的,因为rownum是依次给记录加上序号的,需要先将记录查询出来才能确定所处的序号是多少。

select rownum, t.pkid, t.xh, t.lqh
  from zhxg_yx_yxxcgl_xsjbxx t
 where rownum = 5;

下面进行改写:需要先查询出一些记录,然后进行编号,确定了序号之后才能使用=进行精确查询哪一条。

--获取rownum=5这条记录
select r.rn, r.pkid, r.xh, r.lqh
  from (select rownum rn, t.pkid, t.xh, t.lqh
          from zhxg_yx_yxxcgl_xsjbxx t
         where rownum <= 10) r
 where r.rn = 5;

【6】. 从表中随机返回n条记录

这里要注意rownum的不变性,注意先取数据还是先排序,顺序反了,查询结果都会不一样。下面是错误做法:

--错误做法:先取数据后再随机排序(因为rownum已经不变,不管怎么随机,都是同样的数据之间进行排序)
--运行多次发现数据不变,只是顺序变化而已
select t.pkid, t.xh, t.lqh, t.xm, rownum as rm  --rownum排好后不变
  from zhxg_yx_yxxcgl_xsjbxx t
 where rownum <= 3
 order by dbms_random.value();

运行多几次,我们发现,如果先取数据的话,对比两张图,发现三条记录对应的rownum是不会变化的,所以不管怎么随机排序都是在这三条记录之间进行随机排序。下面是正确做法:

--正确做法: 先排好序之后再取数据
select r.pkid, r.xh, r.xm, r.lqh, r.oldnum, rownum as newnum  --外部查询rownum
  from (select t.pkid, t.xh, t.lqh, t.xm, rownum as oldnum --子查询rownum
          from zhxg_yx_yxxcgl_xsjbxx t
         order by dbms_random.value()) r
 where rownum <= 3;

【7】. 模糊查询中转义字符的处理

构建结果集:

with temp as
 (select 'ABCEDF' as vname
    from dual
  union all
  select '_BCEFG' as vname
    from dual
  union all
  select '_BCEDF' as vname
    from dual
  union all
  select '_\BCEDF' as vname
    from dual
  union all
  select 'XYCEG' as vname
    from dual)
SELECT * from temp

【a】查询vname中包含'_BCE'的记录:

with temp as
 (select 'ABCEDF' as vname
    from dual
  union all
  select '_BCEFG' as vname
    from dual
  union all
  select '_BCEDF' as vname
    from dual
  union all
  select '_\BCEDF' as vname
    from dual
  union all
  select 'XYCEG' as vname
    from dual)
--查询vname中包含'_BCE'的记录
SELECT * from temp t where t.vname like '_BCE%' 

上图中圈起来的记录其实并不符合条件,我们需要对‘_’进行转义处理:

with temp as
 (select 'ABCEDF' as vname
    from dual
  union all
  select '_BCEFG' as vname
    from dual
  union all
  select '_BCEDF' as vname
    from dual
  union all
  select '_\BCEDF' as vname
    from dual
  union all
  select 'XYCEG' as vname
    from dual)
--查询vname中包含'_BCE'的记录
--SELECT * from temp t where t.vname like '_BCE%' 
--转义处理
SELECT * from temp t where t.vname like '\_BCE%' escape '\'

【b】获取'_\BCEDF'这条记录

with temp as
 (select 'ABCEDF' as vname
    from dual
  union all
  select '_BCEFG' as vname
    from dual
  union all
  select '_BCEDF' as vname
    from dual
  union all
  select '_\BCEDF' as vname
    from dual
  union all
  select 'XYCEG' as vname
    from dual)
--获取'_\BCEDF'这条记录
SELECT * from temp t where t.vname like '_\BCE%' escape '\';

转义之后,报错,如上图,这时候还需要使用 ‘\\’ 进行转义:

with temp as
 (select 'ABCEDF' as vname
    from dual
  union all
  select '_BCEFG' as vname
    from dual
  union all
  select '_BCEDF' as vname
    from dual
  union all
  select '_\BCEDF' as vname
    from dual
  union all
  select 'XYCEG' as vname
    from dual)
--获取'_\BCEDF'这条记录
SELECT * from temp t where t.vname like '_\\BCE%' escape '\';

【8】. 巧用translate()函数:

  • 针对字符进行替换,返回将出现在from中的每个字符替换为to中的相应字符以后的字符串;若from比to字符串长,那么在from中比to中多出的字符将会被删除; 三个参数中有一个是空,返回值也将是空值
--translate(char, from, to)替换函数
select translate('abc张三defabb', 'abcdef', '123456') as temp from dual;
--解析: a - 1   b - 2  c - 3  d - 4  e - 5  f - 6 依次替换字符

--三个参数中,只有有其中一个参数为null,结果就返回null
select translate('abc张三defabb', null, '123456') as temp from dual;

--若from比to字符串长,那么在from中比to中多出的字符将会被删除
select translate('abc张三defabb', 'abcdef', '123') as temp from dual;

【9】. 巧处理排序空值

使用nulls first/ nulls last进行空值排序处理:

--空值排前面
select t.pkid, t.xh, t.lqh, t.xm, t.mm
  from ZHXG_YX_YXXCGL_XSJBXX t
 where rownum <= 5
 order by t.mm nulls first;
 
--空值排后面 
select t.pkid, t.xh, t.lqh, t.xm, t.mm
  from ZHXG_YX_YXXCGL_XSJBXX t
 where rownum <= 5
 order by t.mm nulls last;

【10】. 根据条件取不同的列进行排序

针对这种需求,我们可以在查询语句中多查询出一列,然后再根据这列进行排序。

--按分数进行排序,并且70-75分数段要先排序
select t.pkid, t.gkfs, t.xh, t.xm, t.lqh
  from ZHXG_YX_YXXCGL_XSJBXX t
 where rownum <= 10
 order by t.gkfs;

--第一种方式
select *
  from (select t.pkid,
               t.gkfs,
               t.xh,
               t.xm,
               t.lqh,
               case
                 when t.gkfs >= 70 and t.gkfs <= 75 then
                  1
                 else
                  2
               end as pxh
          from ZHXG_YX_YXXCGL_XSJBXX t
         where rownum <= 10) r
 order by r.pxh, r.gkfs

当然,也可以直接在order by子句中判断:

--第二种方式
select t.pkid, t.gkfs, t.xh, t.xm, t.lqh
  from ZHXG_YX_YXXCGL_XSJBXX t
 where rownum <= 10
 order by case
            when t.gkfs >= 70 and t.gkfs <= 75 then
             1
            else
             2
          end,
          t.gkfs

【11】. union all 与空字符串

在oracle中空字符串' '一般相当于null,但并不说明null 与空字符串' '是等价的,空字符串' '本质上还是varchar2()类型的,null可以被作为任何数据类型。看以下示例:

--''本质上还是varchar2()类型, null可以是任何类型
select 'a' from dual union all select '' from dual;
select 'a' from dual union all select null from dual; 

但是下面的代码就会报错了,如果union all两边的数据类型没有对应上,就会报错:

--sysdate 是 时间类型  ''是varchar2类型, 报错
select sysdate from dual union all select '' from dual;

注意和下面代码的区别: null可以充当任何数据类型,所以不会报错。

--sysdate 是 时间类型  null可以是任何类型, 不会报错
select sysdate from dual union all select null from dual;

【12】. 使用union 代替 or可以提高效率
 

select *
  from EMP t
 where t.empno = '7788'
    or t.ename = 'SCOTT';

--会存在重复数据,必须去重
select *
  from EMP t
 where t.empno = '7788'
union all
select *
  from EMP t
 where t.ename = 'SCOTT';

--使用到索引,效率相对较高
select *
  from EMP t
 where t.empno = '7788'
union
select *
  from EMP t
 where t.ename = 'SCOTT';

需要注意的是: 有重复数据的数据集使用union后得到的结果可能会不一致。看以下示例:

两个结果集有四条记录是重复的,使用or连接后查询得到五条数据:

select t.deptno
  from EMP t
 where t.job = 'SALESMAN'
    or t.mgr = 7698;

接着,我们使用union来改写以下:

--去重之后,结果不正确
select t.deptno
  from EMP t
 where t.job = 'SALESMAN'
union
select t.deptno
  from EMP t
 where t.mgr = 7698;

如上图,union之后,结果集变成一条记录了,明显不正确。接着改写:使用唯一列标识/rowid/rownum来进行区别,可以避免union不必要的去重。

--解决方法一: 使用唯一列
select t.empno, t.deptno
  from EMP t
 where t.job = 'SALESMAN'
union
select t.empno, t.deptno
  from EMP t
 where t.mgr = 7698;

--解决方法二:使用rowid(或者对查询一列rownum)
select rowid, t.deptno
  from EMP t
 where t.job = 'SALESMAN'
union
select rowid, t.deptno
  from EMP t
 where t.mgr = 7698;
 
 

【13】 内连接尽量使用inner join,避免使用from 表1,表2这种方式

--推荐使用 inner join ,容易看清楚两张表之间的关联关系
select t.empno,
       t.ename,
       t.job,
       t.mgr,
       t.hiredate,
       t.sal,
       t.comm,
       t.deptno,
       d.dname
  from emp t
 inner join dept d
    on d.deptno = t.deptno
 where t.deptno = 10;

--不推荐使用 
select e.empno,
       e.ename,
       e.job,
       e.mgr,
       e.hiredate,
       e.sal,
       e.comm,
       e.deptno,
       d2.dname
  from emp e, dept d2
 where e.deptno = 10
   and e.deptno = d2.deptno;

【14】 inner join /  left join / right join / full join区别

  • inner join: 只返回左右表相匹配的记录。
  • left join: 左表返回全部数据,右表如果没有匹配的记录用null填充。
  • right join: 右表返回全部数据,左表如果没有匹配的记录用null填充。
  • full join: 左右两张表的数据都返回,只有相匹配的才显示在同一行。

看以下示例:

【inner join】:

with L as
 (select 'left_1' as str, '1' as val
    from dual
  union all
  select 'left_2' as str, '2' as val
    from dual
  union all
  select 'left_3' as str, '3' as val
    from dual
  union all
  select 'left_4' as str, '4' as val
    from dual),
R as
 (select 'right_3' as str, '3' as val
    from dual
  union all
  select 'right_4' as str, '4' as val
    from dual
  union all
  select 'right_5' as str, '5' as val
    from dual
  union all
  select 'right_6' as str, '6' as val
    from dual)
select L.str, L.val, R.str
  from L
 inner join R
    on L.val = R. val
 order by L.val;

另一种写法:

with L as
 (select 'left_1' as str, '1' as val
    from dual
  union all
  select 'left_2' as str, '2' as val
    from dual
  union all
  select 'left_3' as str, '3' as val
    from dual
  union all
  select 'left_4' as str, '4' as val
    from dual),
R as
 (select 'right_3' as str, '3' as val
    from dual
  union all
  select 'right_4' as str, '4' as val
    from dual
  union all
  select 'right_5' as str, '5' as val
    from dual
  union all
  select 'right_6' as str, '6' as val
    from dual)
select L.str, L.val, R.str from L, R where L.val = R. val order by L.val;

【left join】:

with L as
 (select 'left_1' as str, '1' as val
    from dual
  union all
  select 'left_2' as str, '2' as val
    from dual
  union all
  select 'left_3' as str, '3' as val
    from dual
  union all
  select 'left_4' as str, '4' as val
    from dual),
R as
 (select 'right_3' as str, '3' as val
    from dual
  union all
  select 'right_4' as str, '4' as val
    from dual
  union all
  select 'right_5' as str, '5' as val
    from dual
  union all
  select 'right_6' as str, '6' as val
    from dual)
select L.str, L.val, R.str
  from L
  left join R
    on L.val = R. val
 order by L.val;

【right join】:

with L as
 (select 'left_1' as str, '1' as val
    from dual
  union all
  select 'left_2' as str, '2' as val
    from dual
  union all
  select 'left_3' as str, '3' as val
    from dual
  union all
  select 'left_4' as str, '4' as val
    from dual),
R as
 (select 'right_3' as str, '3' as val
    from dual
  union all
  select 'right_4' as str, '4' as val
    from dual
  union all
  select 'right_5' as str, '5' as val
    from dual
  union all
  select 'right_6' as str, '6' as val
    from dual)
select L.str, L.val, R.str
  from L
 right join R
    on L.val = R. val
 order by L.val;

【full join】:

with L as
 (select 'left_1' as str, '1' as val
    from dual
  union all
  select 'left_2' as str, '2' as val
    from dual
  union all
  select 'left_3' as str, '3' as val
    from dual
  union all
  select 'left_4' as str, '4' as val
    from dual),
R as
 (select 'right_3' as str, '3' as val
    from dual
  union all
  select 'right_4' as str, '4' as val
    from dual
  union all
  select 'right_5' as str, '5' as val
    from dual
  union all
  select 'right_6' as str, '6' as val
    from dual)
select L.str, L.val, R.str
  from L
  full join R
    on L.val = R. val
 order by L.val;

【15】. 自关联

自关联表示的是join表自身,只是连接条件的字段可能不一致。

--查询每个员工对应的主管
select t.empno, t.ename, t2.ename as mgrname
  from emp t
  left join emp t2
    on t.mgr = t2.empno;

【16】 not in / not exists / left join

使用这三个实现统计没有员工的部门信息:

--not in 
select *
  from dept d
 where d.deptno not in
      --统计所有有员工的部门编号
       (select e.deptno from emp e where e.deptno is not null);

--not exists
select *
  from dept d
  --不存在 e.deptno = d.deptno的部门信息
 where not exists (select * from emp e where e.deptno = d.deptno);

--left join
select d.*
  from dept d
  left join emp e
    on e.deptno = d.deptno
 where e.deptno is null

以上三条sql执行结果一致。

至于哪一种效率高一点,可以通过查看分析sql执行计划看出来:

explain plan for select *
  from dept d
  --不存在 e.deptno = d.deptno的部门信息
 where not exists (select * from emp e where e.deptno = d.deptno);

select * from table(dbms_xplan.display());

【17】 外连接条件需要注意放的位置

需要特别注意所加上的条件是要过滤外连接join之后的结果还是先过滤之后再进行外连接join操作。看以下示例:

假设我外连接只需要连接右表val=  '3'这条记录,那么如果加条件的位置不对,结果截然不同。如下:

with L as
 (select 'left_1' as str, '1' as val
    from dual
  union all
  select 'left_2' as str, '2' as val
    from dual
  union all
  select 'left_3' as str, '3' as val
    from dual
  union all
  select 'left_4' as str, '4' as val
    from dual),
R as
 (select 'right_3' as str, '3' as val
    from dual
  union all
  select 'right_4' as str, '4' as val
    from dual
  union all
  select 'right_5' as str, '5' as val
    from dual
  union all
  select 'right_6' as str, '6' as val
    from dual)
--假设右表只需要查找val = 3这条记录

--错误写法
select L.str, L.val, R.str
  from L
  left join R
    on L.val = R. val
--加where等于对join之后的整个结果进行过滤
 where R.val = '3'
 order by L.val;

如上图,查询结果只有一条,并不是像预期那样:

下面提供两种方法,解决这种外连接加条件错误:

with L as
 (select 'left_1' as str, '1' as val
    from dual
  union all
  select 'left_2' as str, '2' as val
    from dual
  union all
  select 'left_3' as str, '3' as val
    from dual
  union all
  select 'left_4' as str, '4' as val
    from dual),
R as
 (select 'right_3' as str, '3' as val
    from dual
  union all
  select 'right_4' as str, '4' as val
    from dual
  union all
  select 'right_5' as str, '5' as val
    from dual
  union all
  select 'right_6' as str, '6' as val
    from dual)
--假设右表只需要查找val = 3这条记录
--正确写法:
select L.str, L.val, R.str
  from L
  left join R
    on L.val = R. val
   and R.val = '3'
 order by L.val;
with L as
 (select 'left_1' as str, '1' as val
    from dual
  union all
  select 'left_2' as str, '2' as val
    from dual
  union all
  select 'left_3' as str, '3' as val
    from dual
  union all
  select 'left_4' as str, '4' as val
    from dual),
R as
 (select 'right_3' as str, '3' as val
    from dual
  union all
  select 'right_4' as str, '4' as val
    from dual
  union all
  select 'right_5' as str, '5' as val
    from dual
  union all
  select 'right_6' as str, '6' as val
    from dual)
--假设右表只需要查找val = 3这条记录
--正确写法二:
select L.str, L.val, R.str
  from L
--先过滤val='3'之后再join
  left join (select * from R where R.val = '3') R
    on L.val = R. val
 order by L.val;

以上两种方式才是正确的。

【18】聚集与内连接

首先构造测试数据:

with emp_bonus as
 (select 7934 as empno, 1 as type
    from dual
  union all
  select 7934 as empno, 2 as type
    from dual
  union all
  select 7839 as empno, 3 as type
    from dual
  union all
  select 7782 as empno, 1 as type
    from dual)
select * from emp_bonus;

计算员工对应的奖金,以上是员工对应的奖金等级。

先连接:


with emp_bonus as
 (select 7934 as empno, 1 as type
    from dual
  union all
  select 7934 as empno, 2 as type
    from dual
  union all
  select 7839 as empno, 3 as type
    from dual
  union all
  select 7782 as empno, 1 as type
    from dual)
select e.deptno,
       e.sal,
       (e.sal * case
             when b.type = 1 then
              0.1
             when b.type = 2 then
              0.2
             when b.type = 3 then
              0.3
           end) as bonus
  from emp e
 inner join emp_bonus b
    on b.empno = e.empno
 where e.deptno = 10

然后进行统计:

with emp_bonus as
 (select 7934 as empno, 1 as type
    from dual
  union all
  select 7934 as empno, 2 as type
    from dual
  union all
  select 7839 as empno, 3 as type
    from dual
  union all
  select 7782 as empno, 1 as type
    from dual)
select e.deptno,
       sum(e.sal),
       sum(e.sal * case
             when b.type = 1 then
              0.1
             when b.type = 2 then
              0.2
             when b.type = 3 then
              0.3
           end) as bonus
  from emp e
 inner join emp_bonus b
    on b.empno = e.empno
 where e.deptno = 10
 group by e.deptno;

--select sum(e.sal) as total from emp e where e.deptno = 10;

查看上图,发现总工资金额为10050,执行统计总金额sql:

select sum(e.sal) as total from emp e where e.deptno = 10;

我们发现总工资金额对不上,原因在于奖金等级那张表有个员工7934的有两条记录,正确的做法应该是先聚合员工的等级信息再进行连接join操作。

【1】先统计每个员工的奖金等级

with emp_bonus as
 (select 7934 as empno, 1 as type
    from dual
  union all
  select 7934 as empno, 2 as type
    from dual
  union all
  select 7839 as empno, 3 as type
    from dual
  union all
  select 7782 as empno, 1 as type
    from dual)
select b.empno,
       sum(case
             when b.type = 1 then
              0.1
             when b.type = 2 then
              0.2
             when b.type = 3 then
              0.3
           end) as rate
  from emp_bonus b
 group by b.empno;

【2】再进行聚合

select sum(e.sal) as total, sum(e.sal * r.rate) as total_bonus, e.deptno
  from emp e
 inner join(with emp_bonus as (select 7934 as empno, 1 as type
                                 from dual
                               union all
                               select 7934 as empno, 2 as type
                                 from dual
                               union all
                               select 7839 as empno, 3 as type
                                 from dual
                               union all
                               select 7782 as empno, 1 as type
                                 from dual)
select b.empno,
       sum(case
             when b.type = 1 then
              0.1
             when b.type = 2 then
              0.2
             when b.type = 3 then
              0.3
           end) as rate
  from emp_bonus b
 group by b.empno) r
    on r.empno = e.empno
 where e.deptno = 10
 group by e.deptno

这样结果就正确了。

【19】聚集与外连接

如果需要返回各个部门的总工资以及总奖金,根据上面的示例,直接使用left join即可。

select sum(e.sal) as total, sum(e.sal * r.rate) as total_bonus, e.deptno
  from emp e
  left join(with emp_bonus as (select 7934 as empno, 1 as type
                                 from dual
                               union all
                               select 7934 as empno, 2 as type
                                 from dual
                               union all
                               select 7839 as empno, 3 as type
                                 from dual
                               union all
                               select 7782 as empno, 1 as type
                                 from dual)
select b.empno,
       sum(case
             when b.type = 1 then
              0.1
             when b.type = 2 then
              0.2
             when b.type = 3 then
              0.3
           end) as rate
  from emp_bonus b
 group by b.empno) r
    on r.empno = e.empno
 group by e.deptno

【20】多表查询注意空值问题

示例:返回所有比‘ALLEN’提成低的员工

select e.comm, e.empno, e.ename
  from emp e
 where e.comm < (select e2.comm from emp e2 where e2.ename = 'ALLEN');

对比所有员工的提成结果

我们发现,上面统计结果明显不对,其中还有一部分员工没有提成,也算比‘ALLEN’提成低的范围,这些记录应该也要被查询出来:我们将提成为空的做一下转换,再进行比较。

select e.comm, e.empno, e.ename
  from emp e
 where nvl(e.comm, 0) <
       (select e2.comm from emp e2 where e2.ename = 'ALLEN');

这样结果就正确了。

另外,一些函数如in(null)会直接返回null,需要注意一下。

三、总结

这只是第一部分总结,下一篇继续总结。积少成多,keeping....

猜你喜欢

转载自blog.csdn.net/Weixiaohuai/article/details/85247657