zoukankan      html  css  js  c++  java
  • 2.NULL 的问题

    /*************************************************
    二、主题:NULL 的问题

    *************************************************/
        CREATE TABLE TEST1
        (  
            ID   NUMBER(1) NOT NULL PRIMARY KEY,
            NAME VARCHAR(10)
        );
        CREATE unique INDEX IDX_TEST1 ON TEST1(NAME);
       
        INSERT INTO TEST1 VALUES(0,'0');
        INSERT INTO TEST1 VALUES(1,'1');
        INSERT INTO TEST1 VALUES(2,'2');
        INSERT INTO TEST1 VALUES(3,'A');
        INSERT INTO TEST1 VALUES(4,'B');
        INSERT INTO TEST1 VALUES(5,'a');  
        INSERT INTO TEST1(ID)  VALUES(7);  
       
    =============================================================================
    2.1.UNKNOWN 与 空格、0、其他不可见字符等不同

        SELECT DUMP(NULL) AS A,
               DUMP('') AS B,
               0 AS C
          FROM DUAL;--结果:NULL NULL 0
        --NULL 与空字符串,NULL是无类型或者说是任何类型的。
        SELECT CASE WHEN ''  = NULL THEN 1 ELSE 0 END AS COP1,  --引号内无内容,结果为:0
               CASE WHEN ' ' = NULL THEN 1 ELSE 0 END AS COP2  --引号内是空格,结果为:0
          FROM DUAL; 
         
    2.2.任何与NULL的比较操作,都返回NULL。

        --返回nuknown 值  
        SELECT * FROM TEST1 WHERE ID=NULL;
        SELECT * FROM TEST1 WHERE ID<>NULL;
       
        --返回正确查询
        SELECT * FROM TEST1 WHERE ID IS NOT NULL;
        SELECT * FROM TEST1 WHERE NAME IS NULL;
       
    2.3.算术运算
       
        SELECT 10+NULL,10*NULL,10/NULL FROM DUAL;    --结果:nuknown nuknown nuknown
        SELECT 'A'|| NULL,CONCAT(NULL,'a') FROM DUAL;--结果忽略NULL:A       a
       
    2.4.NULL相关函数
     2.4.1. NVL(VALUE,REPLACEVALUE),替换NULL为某值,但是需要替换的值类型必须与之一致。
     
        SELECT ID , NVL(NAME,'NoValue') FROM TEST1;
       
     2.4.2. NVL2(VALUE,EXPR2,EXPR3),若VALUE为空,则返回EXPR3,否则返回EXPR2 ,EXPR2 与EXPR3的类型保持一致。
     
        SELECT ID,NVL2(NAME,1,'2') FROM TEST1; --若NAME字段不为空,则返回1,若为空则返回2,,此处返回的是NUMBER类型,因为1比'2' 的优先级高。
        SELECT ID,NVL2(NAME,1,NULL) FROM TEST1;--若NAME字段不为空,则返回1,否则返回null。
        SELECT ID,NVL2(NAME,NULL,'Y') FROM TEST1;--若NAME字段不为空,则返回NULL,否则返回'Y'.
       
     2.4.3. NULLIF(VALUE1,VALUE2),若VALUE1=VALUE2,则返回NULL,否则返回VALUE1,即继续用VALUE1;强制要求:两个值类型必须一致。
     
        SELECT NULLIF(1,2) FROM DUAL; --结果:1
        SELECT NULLIF(1,1) FROM DUAL;
              
        --在除法中的作用 ,比较有用,此处用法可以替代DECODE,CASE 。
        SELECT  10/0  FROM DUAL;  --错误,因为除数不能为0,小学生常识。
        SELECT 10/NULLIF(0,0) FROM DUAL;--结果为空值   
       
        SELECT ID,10/CASE WHEN ID = 0 THEN NULL ELSE ID END ID2 FROM TEST1;--正确,ID=0 的得到空值
        SELECT ID,10/DECODE(ID,0,NULL,ID) ID2 FROM TEST1; --正确,ID=0 的得到空值
        SELECT ID,10/NULLIF(ID,0) FROM TEST1;--正确,ID=0 的得到空值
     
        --实际用得不多
        SELECT NULLIF(NULL,1) FROM DUAL;--报错
        SELECT NULLIF(TO_CHAR(NULL),'1') FROM DUAL;--返回空值

        SELECT NULLIF(TO_NUMBER(NULL),1) FROM DUAL;   --报错
        SELECT NULLIF(TO_NUMBER(NULL,'9'),1) FROM DUAL;--返回空值  
     
     2.4.4. COALESCE (X1,X3,Xn...),从左往右取,得到第一个非空值,其中值类型必须一致,否则会报错。
       
        SELECT COALESCE(1,'1') FROM DUAL;--报错,类型不一致
       
        SELECT COALESCE(NULL,1,2) FROM DUAL;--结果:1
       
     2.4.5. CASE WHEN ,DECODE 处理 NULL值 。CASE 表达式得到数值型的,DECODE得到字符型的。
        --建立测试表TEST3
        =====================================================
        create table TEST3
        (
          sgnyear       NVARCHAR2(4) not null,
          areacode      NVARCHAR2(10) not null,
          transtypecode NVARCHAR2(10) not null,
          cargovolume   NUMBER(18,4),
          updateid      NUMBER(18),
          updatestate   NUMBER(1) default 0,
          updatetime    DATE default SYSDATE,
          businesstime  DATE default SYSDATE
        )  ;
        --插入数据,类似数据
        insert into TEST3 (SGNYEAR, AREACODE, TRANSTYPECODE, CARGOVOLUME, UPDATEID, UPDATESTATE, UPDATETIME, BUSINESSTIME)
        values ('2002', '360000', '5', 0.0000, 131715, 0, to_date('11-03-2014 10:54:08', 'dd-mm-yyyy hh24:mi:ss'), to_date('01-01-2002', 'dd-mm-yyyy'));

        insert into TEST3 (SGNYEAR, AREACODE, TRANSTYPECODE, CARGOVOLUME, UPDATEID, UPDATESTATE, UPDATETIME, BUSINESSTIME)
        values ('2002', '150000', '6', 37239.0000, 112343, 0, to_date('11-03-2014 10:54:08', 'dd-mm-yyyy hh24:mi:ss'), to_date('01-01-2002', 'dd-mm-yyyy'));

        insert into TEST3 (SGNYEAR, AREACODE, TRANSTYPECODE, CARGOVOLUME, UPDATEID, UPDATESTATE, UPDATETIME, BUSINESSTIME)
        values ('2011', '530000', '1', 60169.8590, 107295, 0, to_date('11-03-2014 10:54:08', 'dd-mm-yyyy hh24:mi:ss'), to_date('01-01-2011', 'dd-mm-yyyy'));

        insert into TEST3 (SGNYEAR, AREACODE, TRANSTYPECODE, CARGOVOLUME, UPDATEID, UPDATESTATE, UPDATETIME, BUSINESSTIME)
        values ('1995', '330000', '3', 1914.0000, 111791, 0, to_date('11-03-2014 10:54:08', 'dd-mm-yyyy hh24:mi:ss'), to_date('01-01-1995', 'dd-mm-yyyy'));

        insert into TEST3 (SGNYEAR, AREACODE, TRANSTYPECODE, CARGOVOLUME, UPDATEID, UPDATESTATE, UPDATETIME, BUSINESSTIME)
        values ('2008', '150000', '2', 38357.3386, 120727, 0, to_date('11-03-2014 10:54:08', 'dd-mm-yyyy hh24:mi:ss'), to_date('01-01-2008', 'dd-mm-yyyy'));
        .....
        =====================================================   
        --查询1.,根据年份分组,根据 TransTypeCode 为行列转换 标准,updatestate=2的数据视为无效数据
          select
                 SgnYear,         
                 MAX(case when updatestate=2 then null else decode(TransTypeCode , '1',ROUND(CargoVolume,2),null) end) as Et01,
                 MAX(case when updatestate=2 then null else decode(TransTypeCode , '2',ROUND(CargoVolume,2),null) end) as Et02,
                 MAX(case when updatestate=2 then null else decode(TransTypeCode , '3',ROUND(CargoVolume,2),null) end) as Et03,
                 MAX(case when updatestate=2 then null else decode(TransTypeCode , '4',ROUND(CargoVolume,2),null) end) as Et04,
                 MAX(case when updatestate=2 then null else decode(TransTypeCode , '5',ROUND(CargoVolume,2),null) end) as Et05,
                 MAX(case when updatestate=2 then null else decode(TransTypeCode , '6',ROUND(CargoVolume,2),null) end) as Et06,
                 MAX(case when updatestate=2 then null else decode(TransTypeCode , '7',ROUND(CargoVolume,2),null) end) as Et07,
                 MAX(case when updatestate=2 then null else decode(TransTypeCode , '8',ROUND(CargoVolume,2),null) end) as Et08,
                 MAX(case when updatestate=2 then null else decode(TransTypeCode , '9',ROUND(CargoVolume,2),null) end) as Et09,
                 case when min(updatestate)=2 then 2 else 1 end as updatestate         
             from TEST3
            group by SgnYear ;  
        --得到的结果,值全为数值型。

        --查询2.与查询1一样的思想,换一种方法
          select
                 SgnYear,         
                 MAX(decode(TransTypeCode , '1',decode(UPDATESTATE,2,NULL,ROUND(CargoVolume,2)))) as Et01,
                 MAX(decode(TransTypeCode , '2',decode(UPDATESTATE,2,NULL,ROUND(CargoVolume,2)))) as Et02,
                 MAX(decode(TransTypeCode , '3',decode(UPDATESTATE,2,NULL,ROUND(CargoVolume,2)))) as Et03,
                 MAX(decode(TransTypeCode , '4',decode(UPDATESTATE,2,NULL,ROUND(CargoVolume,2)))) as Et04,                          
                 case when min(updatestate)=2 then 2 else 1 end as updatestate         
             from TEST3
            group by SgnYear ;
         --查询2,得到的结果,值全部为 字符型

         --比较
         SELECT  decode(UPDATESTATE,2,NULL,ROUND(CargoVolume,2)),--得到的值为字符型
                 decode(TransTypeCode , '1',decode(UPDATESTATE,2,NULL,ROUND(CargoVolume,2))),--得到的值为字符型
                 case when updatestate=2 then null else CargoVolume end,--得到的值为数值型
                 case when updatestate=2 then null else decode(TransTypeCode , '1',ROUND(CargoVolume,2),null) end--得到的值为数值s型
            FROM TEST3;

    2.5.NULL与索引
        基本索引(B-TREE),是不存储全为NULL的列的。复合索引若有非NULL的列可以存储,但是全为空不存储。
        =================================================      
        CREATE TABLE TEST2
        (
         ID    NUMBER,
         VALUE NUMBER
        );
        CREATE INDEX IDX1_TEST2 ON TEST2(ID);--索引不会存储NULL值

        INSERT INTO TEST2 VALUES(6,1);
        INSERT INTO TEST2 VALUES(2,2);
        INSERT INTO TEST2 VALUES(3,1);
        INSERT INTO TEST2 VALUES(4,NULL);
        INSERT INTO TEST2 VALUES(1,NULL);
        =================================================
           
        SELECT * FROM TEST2 WHERE ID IS NOT NULL;--走索引
        SELECT * FROM TEST2 WHERE ID IS NULL;--不走索引。
       
        -- IS NULL 的查询若要走索引,可以建立一个有伪列的索引
       
        --建立有伪列的索引
        CREATE INDEX IDX2_TEST2  ON TEST2(ID,2);
       
        -------------更新表的统计信息,若不更新,还是与之前一样
        SQL>  EXEC   DBMS_STATS.GATHER_TABLE_STATS(USER,'TEST2',CASCADE=>TRUE) ;
     
        PL/SQL procedure successfully completed
        ---------------
       
        --再次查看执行计划
        SELECT * FROM TEST2 WHERE ID IS NOT NULL;--不走索引
        SELECT * FROM TEST2 WHERE ID IS NULL;    --走索引
       
        --此时,IS NOT NULL 的查询不走索引, IS NULL的查询走索引。 ^_^

    2.6.建表时,NOT NULL 一定在DEFAULT 之后,不然会报错

    2.7.NULL 与 排序
        --在ORDER BY 中 ,NULL 默认为最大值,所以ASC 时排在最后,DESC时排在最前面
        SELECT * FROM TEST1 ORDER BY NAME ASC;  --为NULL的排在后面
       
        SELECT * FROM TEST1 ORDER BY NAME DESC; --为NULL的排在前面
       
        --当然,可以显示制定NULL的排序规则
        SELECT * FROM TEST1 ORDER BY NAME ASC NULLS FIRST;--为NULL的排在前面
        SELECT * FROM TEST1 ORDER BY NAME DESC NULLS LAST;--为NULL的排在后面    
       
    ============================================================================= 

  • 相关阅读:
    51nod 1087 1 10 100 1000(找规律+递推+stl)
    51nod 1082 与7无关的数 (打表预处理)
    51 nod 1080 两个数的平方和
    1015 水仙花数(水题)
    51 nod 1003 阶乘后面0的数量
    51nod 1002 数塔取数问题
    51 nod 1001 数组中和等于K的数对
    51 nod 1081 子段求和
    51nod 1134 最长递增子序列 (O(nlogn)算法)
    51nod 1174 区间中最大的数(RMQ)
  • 原文地址:https://www.cnblogs.com/zihuancc/p/3812403.html
Copyright © 2011-2022 走看看