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的排在后面    
       
    ============================================================================= 

  • 相关阅读:
    HTML
    数据库
    EF增删查改(三)------终极版
    三层的之间的引用
    sql:PostgreSQL
    csharp:SQLite and Access using C# code read data
    sql:Mysql create view,function,procedure
    sql: MySQL and Microsoft SQL Server Stored Procedures IN, OUT using csharp code
    Working C# code for MySql5.5 Stored Procedures IN parameters
    csharp:search and Compare string
  • 原文地址:https://www.cnblogs.com/zihuancc/p/3812403.html
Copyright © 2011-2022 走看看