zoukankan      html  css  js  c++  java
  • Oracle SQL篇(一)null值之初体验

     

       
       从我第一次正式的写sql语句到现在,已经超过10年的时间了。我写报表,做统计分析和财务对账,我一点点的接触oracle数据库,并尝试深入了解。这条路,一走就是10年,从充满热情,到开始厌倦,我不知道我还能坚持多久,未来的路,谁知道呢?

        也许是该抓紧时间,做一点什么了,我不知道该开始写些什么,我从来没有在网上写东西的习惯。
        先从简单的开始吧,那当然就是SQL,这是我SQL系列的第一篇,希望我能够坚持。

    在Oracle数据库中,如果一个表中的列没有值的话,我们可以说是空值,比如IT员工,假如没有提成的话,提成列就应该是空。对于空值,Oracle数据库使用null来表示,空即没有的意思。null不是空格,空格是字符类型,表示一个字符,null也不是0,0是数字类型,是一个数值。在通常的B*Tree索引中,null值是不存储的,所以如果where的谓语是column=null的话,将不能使用到索引。

    我们来看下面的一个小例子,为了举例,我建了一张测试表DEMO

    scott@DB01> create table demo as select empno,ename,sal,comm,mgr,deptno from emp;

    Table created.

    scott@DB01> select * from demo;

         EMPNO ENAME             SAL       COMM        MGR     DEPTNO

    ---------- ---------- ---------- ---------- ---------- ----------

          7369 SMITH             800                  7902         20

          7499 ALLEN            1600        300       7698         30

          7521 WARD             1250        500       7698         30

          7566 JONES            2975                  7839         20

          7654 MARTIN           1250       1400       7698         30

          7698 BLAKE            2850                  7839         30

          7782 CLARK            2450                  7839         10

          7788 SCOTT            3000                  7566         20

          7839 KING             5000                               10

          7844 TURNER           1500          0       7698         30

          7876 ADAMS            1100                  7788         20

          7900 JAMES             950                  7698         30

          7902 FORD             3000                  7566         20

          7934 MILLER           1300                  7782         10

    14 rows selected.

    与Sql Server数据库不同的是,在Oracle数据库当中,null也不等于null,如果我们要通过条件筛选找到具有空值的记录,需要使用is(not) null 方法。

    scott@DB01> select empno,ename,sal from demo where comm=null;

    no rows selected

    这里我们留下一个小的疑问,where后面的表达式,返回的是null(空)还是false(假)?

    scott@DB01> select empno,ename,sal from demo where comm is null;

         EMPNO ENAME             SAL

    ---------- ---------- ----------

          7369 SMITH             800

          7566 JONES            2975

          7698 BLAKE            2850

          7782 CLARK            2450

          7788 SCOTT            3000

          7839 KING             5000

          7876 ADAMS            1100

          7900 JAMES             950

          7902 FORD             3000

          7934 MILLER           1300

    10 rows selected.

    其实在Oracle数据库中,我们一般这样来定义,在一个表达式当中,如果有null值的存在,将导致整个表达式为空。当然这也不是绝对的正确,对于Oracle来说,条件判定表达式就是例外。

    下面的语句是由于null从而导致整个表达式为空的例子,当然就这个问题而言,很好解决,我们可以使用NVL函数.

    scott@DB01> select empno,ename,sal,sal*12+comm from demo;

         EMPNO ENAME             SAL SAL*12+COMM

    ---------- ---------- ---------- -----------

          7369 SMITH             800

          7499 ALLEN            1600       19500

          7521 WARD             1250       15500

          7566 JONES            2975

          7654 MARTIN           1250       16400

          7698 BLAKE            2850

          7782 CLARK            2450

          7788 SCOTT            3000

          7839 KING             5000

          7844 TURNER           1500       18000

          7876 ADAMS            1100

          7900 JAMES             950

          7902 FORD             3000

          7934 MILLER           1300

    14 rows selected.

    正确写法,使用了NVL函数

    scott@DB01> select empno,ename,sal,sal*12+nvl(comm,0)  tsal from demo;

         EMPNO ENAME             SAL       TSAL

    ---------- ---------- ---------- ----------

          7369 SMITH             800       9600

          7499 ALLEN            1600      19500

          7521 WARD             1250      15500

          7566 JONES            2975      35700

          7654 MARTIN           1250      16400

          7698 BLAKE            2850      34200

          7782 CLARK            2450      29400

          7788 SCOTT            3000      36000

          7839 KING             5000      60000

          7844 TURNER           1500      18000

          7876 ADAMS            1100      13200

          7900 JAMES             950      11400

          7902 FORD             3000      36000

          7934 MILLER           1300      15600

    14 rows selected.

    我们再来看下面的非常简单的子查询的例子

    scott@DB01> select empno,ename from demo where empno not in (select mgr from demo);

    no rows selected

    如果我们简单来理解字面的意思的话,上面的Sql语句要实现的是:查找DEMO表中纯粹的员工,也就是干活的,呵呵,但是上边的语句并没有得到正确的结果。为什么呢?你是否可以这样来理解,not in 相当于 !=  and !=  and != 这样的结构呢?

    通过下面的查询,我们发现7839的mgr为空,也就是说,在我们上边的子查询中,有一个值为空

    scott@DB01> select empno,ename,mgr from demo;

         EMPNO ENAME          MGR

    ---------- ----------         ----------

          7369 SMITH            7902

          7499 ALLEN            7698

          7521 WARD             7698

          7566 JONES            7839

          7654 MARTIN           7698

          7698 BLAKE            7839

          7782 CLARK            7839

          7788 SCOTT            7566

          7839 KING

          7844 TURNER           7698

          7876 ADAMS            7788

          7900 JAMES            7698

          7902 FORD             7566

          7934 MILLER           7782

    14 rows selected.

    select empno,ename from demo where empno not in (select mgr from demo);这个SQL的条件部分可以转换为empno!=7902 and empno!=7698 and ......and empno !=null(引号部分做了省略),对于empno!=null 返回的值还是null,对于这样的逻辑表达式来说,true and null的结果是null,从而导致整个表达式为空,在这里null作为假条件来处理,所以我们看不到查询结果也就可以理解了。

    再来看下面的语句,我们把NOT IN修改成IN ,却发现是可以得到正确的结果的。不过,我们应该明白,要实现的目的完全相反了,我们找到的是经理,哪怕他手下只有一个小兵。

    scott@DB01> select empno,ename from demo where empno  in (select mgr from demo);

         EMPNO ENAME

    ---------- ----------

          7902 FORD

          7698 BLAKE

          7839 KING

          7566 JONES

          7788 SCOTT

          7782 CLARK

    6 rows selected.

    为什么呢?select empno,ename from demo where empno  in (select mgr from demo);这个SQL我们可以把条件部分转换为empno = 7902 or empno=7698 or ......or empno=null,对于empno=null 返回的值还是null,但是对于这样的逻辑表达式来说,true or null的结果是true,所以我们可以看到查询的结果。

    那对于我们想要找到纯粹的员工,应该怎样来写呢?很简单,null值对于本例的结果没有影响,通过条件过滤掉就可以了。语句如下

    scott@DB01> select empno,ename from demo

    2>where empno not in (select mgr from demo where mgr is not null);

         EMPNO ENAME

    ---------- ----------

          7369 SMITH

          7499 ALLEN

          7521 WARD

          7654 MARTIN

          7844 TURNER

          7876 ADAMS

          7900 JAMES

          7934 MILLER

    8 rows selected

    空值在排序的时候总是出现在大值的一端,但有时候也会带来一些麻烦

    scott@DB01> select * from demo;

         EMPNO ENAME             SAL       COMM     DEPTNO
    ---------- ---------- ---------- ---------- ----------
          7369 SMITH             800                    20
          7499 ALLEN            1600        300         30
          7521 WARD             1250        500         30
          7566 JONES            2975                    20
          7654 MARTIN           1250       1400         30
          7698 BLAKE            2850                    30
          7782 CLARK            2450                    10
          7788 SCOTT            3000                    20
          7839 KING             5000                    10
          7844 TURNER           1500          0         30
          7876 ADAMS            1100                    20
          7900 JAMES             950                    30
          7902 FORD             3000                    20
          7934 MILLER           1300                    10

    14 rows selected.
    当我们根据comm列做降序排序的时候,空值显示到了上边
    scott@DB01> select * from demo order by comm desc;

         EMPNO ENAME             SAL       COMM     DEPTNO
    ---------- ---------- ---------- ---------- ----------
          7369 SMITH             800                    20
          7782 CLARK            2450                    10
          7902 FORD             3000                    20
          7900 JAMES             950                    30
          7876 ADAMS            1100                    20
          7566 JONES            2975                    20
          7698 BLAKE            2850                    30
          7934 MILLER           1300                    10
          7788 SCOTT            3000                    20
          7839 KING             5000                    10
          7654 MARTIN           1250       1400         30
          7521 WARD             1250        500         30
          7499 ALLEN            1600        300         30
          7844 TURNER           1500          0         30

    14 rows selected.
    为了过滤掉空值,我们可以借助nulls last
    scott@DB01> select * from demo order by comm desc nulls last;

         EMPNO ENAME             SAL       COMM     DEPTNO
    ---------- ---------- ---------- ---------- ----------
          7654 MARTIN           1250       1400         30
          7521 WARD             1250        500         30
          7499 ALLEN            1600        300         30
          7844 TURNER           1500          0         30
          7788 SCOTT            3000                    20
          7839 KING             5000                    10
          7876 ADAMS            1100                    20
          7900 JAMES             950                    30
          7902 FORD             3000                    20
          7934 MILLER           1300                    10
          7698 BLAKE            2850                    30
          7566 JONES            2975                    20
          7369 SMITH             800                    20
          7782 CLARK            2450                    10

    14 rows selected.

    我们在开始的时候提了个小问题,comm=null,返回的结果是null还是false呢?

    其实这个问题可以扩展,”=”可以用”>”、”<”等其他操作符替代,意思是一样的。

    我们只用”=”来举例,看下面的例子,看看输出结果,我想你自然就明白了。

    scott@DB01> set serveroutput on

    scott@DB01> declare

      2       i boolean;

      3  begin

      4       i := false;

      5       if (null=1) = i then

      6          dbms_output.put_line('return false!');

      7       elsif (null=1) is null then

      8          dbms_output.put_line('return null!');

      9       end if;

     10  end;

     11  /

    return null!

    PL/SQL procedure successfully completed.

    附:逻辑表达式操作符及结果

    Oracle SQL篇(一)null值之初体验

    (2012-02-26 13:08:19)
    转载
     
       从我第一次正式的写sql语句到现在,已经超过10年的时间了。我写报表,做统计分析和财务对账,我一点点的接触oracle数据库,并尝试深入了解。这条路,一走就是10年,从充满热情,到开始厌倦,我不知道我还能坚持多久,未来的路,谁知道呢?

        也许是该抓紧时间,做一点什么了,我不知道该开始写些什么,我从来没有在网上写东西的习惯。
        先从简单的开始吧,那当然就是SQL,这是我SQL系列的第一篇,希望我能够坚持。

    在Oracle数据库中,如果一个表中的列没有值的话,我们可以说是空值,比如IT员工,假如没有提成的话,提成列就应该是空。对于空值,Oracle数据库使用null来表示,空即没有的意思。null不是空格,空格是字符类型,表示一个字符,null也不是0,0是数字类型,是一个数值。在通常的B*Tree索引中,null值是不存储的,所以如果where的谓语是column=null的话,将不能使用到索引。

    我们来看下面的一个小例子,为了举例,我建了一张测试表DEMO

    scott@DB01> create table demo as select empno,ename,sal,comm,mgr,deptno from emp;

    Table created.

    scott@DB01> select * from demo;

         EMPNO ENAME             SAL       COMM        MGR     DEPTNO

    ---------- ---------- ---------- ---------- ---------- ----------

          7369 SMITH             800                  7902         20

          7499 ALLEN            1600        300       7698         30

          7521 WARD             1250        500       7698         30

          7566 JONES            2975                  7839         20

          7654 MARTIN           1250       1400       7698         30

          7698 BLAKE            2850                  7839         30

          7782 CLARK            2450                  7839         10

          7788 SCOTT            3000                  7566         20

          7839 KING             5000                               10

          7844 TURNER           1500          0       7698         30

          7876 ADAMS            1100                  7788         20

          7900 JAMES             950                  7698         30

          7902 FORD             3000                  7566         20

          7934 MILLER           1300                  7782         10

    14 rows selected.

    与Sql Server数据库不同的是,在Oracle数据库当中,null也不等于null,如果我们要通过条件筛选找到具有空值的记录,需要使用is(not) null 方法。

    scott@DB01> select empno,ename,sal from demo where comm=null;

    no rows selected

    这里我们留下一个小的疑问,where后面的表达式,返回的是null(空)还是false(假)?

    scott@DB01> select empno,ename,sal from demo where comm is null;

         EMPNO ENAME             SAL

    ---------- ---------- ----------

          7369 SMITH             800

          7566 JONES            2975

          7698 BLAKE            2850

          7782 CLARK            2450

          7788 SCOTT            3000

          7839 KING             5000

          7876 ADAMS            1100

          7900 JAMES             950

          7902 FORD             3000

          7934 MILLER           1300

    10 rows selected.

    其实在Oracle数据库中,我们一般这样来定义,在一个表达式当中,如果有null值的存在,将导致整个表达式为空。当然这也不是绝对的正确,对于Oracle来说,条件判定表达式就是例外。

    下面的语句是由于null从而导致整个表达式为空的例子,当然就这个问题而言,很好解决,我们可以使用NVL函数.

    scott@DB01> select empno,ename,sal,sal*12+comm from demo;

         EMPNO ENAME             SAL SAL*12+COMM

    ---------- ---------- ---------- -----------

          7369 SMITH             800

          7499 ALLEN            1600       19500

          7521 WARD             1250       15500

          7566 JONES            2975

          7654 MARTIN           1250       16400

          7698 BLAKE            2850

          7782 CLARK            2450

          7788 SCOTT            3000

          7839 KING             5000

          7844 TURNER           1500       18000

          7876 ADAMS            1100

          7900 JAMES             950

          7902 FORD             3000

          7934 MILLER           1300

    14 rows selected.

    正确写法,使用了NVL函数

    scott@DB01> select empno,ename,sal,sal*12+nvl(comm,0)  tsal from demo;

         EMPNO ENAME             SAL       TSAL

    ---------- ---------- ---------- ----------

          7369 SMITH             800       9600

          7499 ALLEN            1600      19500

          7521 WARD             1250      15500

          7566 JONES            2975      35700

          7654 MARTIN           1250      16400

          7698 BLAKE            2850      34200

          7782 CLARK            2450      29400

          7788 SCOTT            3000      36000

          7839 KING             5000      60000

          7844 TURNER           1500      18000

          7876 ADAMS            1100      13200

          7900 JAMES             950      11400

          7902 FORD             3000      36000

          7934 MILLER           1300      15600

    14 rows selected.

    我们再来看下面的非常简单的子查询的例子

    scott@DB01> select empno,ename from demo where empno not in (select mgr from demo);

    no rows selected

    如果我们简单来理解字面的意思的话,上面的Sql语句要实现的是:查找DEMO表中纯粹的员工,也就是干活的,呵呵,但是上边的语句并没有得到正确的结果。为什么呢?你是否可以这样来理解,not in 相当于 !=  and !=  and != 这样的结构呢?

    通过下面的查询,我们发现7839的mgr为空,也就是说,在我们上边的子查询中,有一个值为空

    scott@DB01> select empno,ename,mgr from demo;

         EMPNO ENAME          MGR

    ---------- ----------         ----------

          7369 SMITH            7902

          7499 ALLEN            7698

          7521 WARD             7698

          7566 JONES            7839

          7654 MARTIN           7698

          7698 BLAKE            7839

          7782 CLARK            7839

          7788 SCOTT            7566

          7839 KING

          7844 TURNER           7698

          7876 ADAMS            7788

          7900 JAMES            7698

          7902 FORD             7566

          7934 MILLER           7782

    14 rows selected.

    select empno,ename from demo where empno not in (select mgr from demo);这个SQL的条件部分可以转换为empno!=7902 and empno!=7698 and ......and empno !=null(引号部分做了省略),对于empno!=null 返回的值还是null,对于这样的逻辑表达式来说,true and null的结果是null,从而导致整个表达式为空,在这里null作为假条件来处理,所以我们看不到查询结果也就可以理解了。

    再来看下面的语句,我们把NOT IN修改成IN ,却发现是可以得到正确的结果的。不过,我们应该明白,要实现的目的完全相反了,我们找到的是经理,哪怕他手下只有一个小兵。

    scott@DB01> select empno,ename from demo where empno  in (select mgr from demo);

         EMPNO ENAME

    ---------- ----------

          7902 FORD

          7698 BLAKE

          7839 KING

          7566 JONES

          7788 SCOTT

          7782 CLARK

    6 rows selected.

    为什么呢?select empno,ename from demo where empno  in (select mgr from demo);这个SQL我们可以把条件部分转换为empno = 7902 or empno=7698 or ......or empno=null,对于empno=null 返回的值还是null,但是对于这样的逻辑表达式来说,true or null的结果是true,所以我们可以看到查询的结果。

    那对于我们想要找到纯粹的员工,应该怎样来写呢?很简单,null值对于本例的结果没有影响,通过条件过滤掉就可以了。语句如下

    scott@DB01> select empno,ename from demo

    2>where empno not in (select mgr from demo where mgr is not null);

         EMPNO ENAME

    ---------- ----------

          7369 SMITH

          7499 ALLEN

          7521 WARD

          7654 MARTIN

          7844 TURNER

          7876 ADAMS

          7900 JAMES

          7934 MILLER

    8 rows selected

    空值在排序的时候总是出现在大值的一端,但有时候也会带来一些麻烦

    scott@DB01> select * from demo;

         EMPNO ENAME             SAL       COMM     DEPTNO
    ---------- ---------- ---------- ---------- ----------
          7369 SMITH             800                    20
          7499 ALLEN            1600        300         30
          7521 WARD             1250        500         30
          7566 JONES            2975                    20
          7654 MARTIN           1250       1400         30
          7698 BLAKE            2850                    30
          7782 CLARK            2450                    10
          7788 SCOTT            3000                    20
          7839 KING             5000                    10
          7844 TURNER           1500          0         30
          7876 ADAMS            1100                    20
          7900 JAMES             950                    30
          7902 FORD             3000                    20
          7934 MILLER           1300                    10

    14 rows selected.
    当我们根据comm列做降序排序的时候,空值显示到了上边
    scott@DB01> select * from demo order by comm desc;

         EMPNO ENAME             SAL       COMM     DEPTNO
    ---------- ---------- ---------- ---------- ----------
          7369 SMITH             800                    20
          7782 CLARK            2450                    10
          7902 FORD             3000                    20
          7900 JAMES             950                    30
          7876 ADAMS            1100                    20
          7566 JONES            2975                    20
          7698 BLAKE            2850                    30
          7934 MILLER           1300                    10
          7788 SCOTT            3000                    20
          7839 KING             5000                    10
          7654 MARTIN           1250       1400         30
          7521 WARD             1250        500         30
          7499 ALLEN            1600        300         30
          7844 TURNER           1500          0         30

    14 rows selected.
    为了过滤掉空值,我们可以借助nulls last
    scott@DB01> select * from demo order by comm desc nulls last;

         EMPNO ENAME             SAL       COMM     DEPTNO
    ---------- ---------- ---------- ---------- ----------
          7654 MARTIN           1250       1400         30
          7521 WARD             1250        500         30
          7499 ALLEN            1600        300         30
          7844 TURNER           1500          0         30
          7788 SCOTT            3000                    20
          7839 KING             5000                    10
          7876 ADAMS            1100                    20
          7900 JAMES             950                    30
          7902 FORD             3000                    20
          7934 MILLER           1300                    10
          7698 BLAKE            2850                    30
          7566 JONES            2975                    20
          7369 SMITH             800                    20
          7782 CLARK            2450                    10

    14 rows selected.

    我们在开始的时候提了个小问题,comm=null,返回的结果是null还是false呢?

    其实这个问题可以扩展,”=”可以用”>”、”<”等其他操作符替代,意思是一样的。

    我们只用”=”来举例,看下面的例子,看看输出结果,我想你自然就明白了。

    scott@DB01> set serveroutput on

    scott@DB01> declare

      2       i boolean;

      3  begin

      4       i := false;

      5       if (null=1) = i then

      6          dbms_output.put_line('return false!');

      7       elsif (null=1) is null then

      8          dbms_output.put_line('return null!');

      9       end if;

     10  end;

     11  /

    return null!

    PL/SQL procedure successfully completed.

    附:逻辑表达式操作符及结果
  • 相关阅读:
    Javascript中怎么定义类(私有成员、静态成员)?
    Web前端国内的叫法与行业归类吗
    CSS hack,CSS简写,CSS定义应注意的几个问题
    7个在IE和Firefox中不同的JavaScript语法
    IE和Firefox中的事件
    IE8的css hack /9
    CSS hack
    运行,复制,保存,runCode,copyCode,saveCode,运行代码框
    自由使用层的叠加
    WordPress自定义URL的Rewrite规则
  • 原文地址:https://www.cnblogs.com/lcword/p/5704250.html
Copyright © 2011-2022 走看看