在SQL中获取null == null

Jam*_*ran 44 sql oracle null nullable

我希望在可空列上搜索数据库表.有时我搜索的值本身就是NULL.因为Null等于什么,甚至是NULL,说

where MYCOLUMN=SEARCHVALUE 
Run Code Online (Sandbox Code Playgroud)

将失败.现在我不得不诉诸

where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
Run Code Online (Sandbox Code Playgroud)

有更简单的说法吗?

(如果重要,我正在使用Oracle)

And*_*ter 68

你可以做IsNull或NVL的东西,但它只是让引擎做更多工作.您将调用函数来进行列转换,然后必须比较结果.

用你拥有的

where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
Run Code Online (Sandbox Code Playgroud)


DCo*_*kie 36

@Andy Lester声称查询的原始形式比使用NVL更有效.我决定测试那个断言:

    SQL> DECLARE
      2    CURSOR B IS
      3       SELECT batch_id, equipment_id
      4         FROM batch;
      5    v_t1  NUMBER;
      6    v_t2  NUMBER;
      7    v_c1  NUMBER;
      8    v_c2  NUMBER;
      9    v_b   INTEGER;
     10  BEGIN
     11  -- Form 1 of the where clause
     12    v_t1 := dbms_utility.get_time;
     13    v_c1 := dbms_utility.get_cpu_time;
     14    FOR R IN B LOOP
     15       SELECT COUNT(*)
     16         INTO v_b
     17         FROM batch
     18        WHERE equipment_id = R.equipment_id OR (equipment_id IS NULL AND R.equipment_id IS NULL);
     19    END LOOP;
     20    v_t2 := dbms_utility.get_time;
     21    v_c2 := dbms_utility.get_cpu_time;
     22    dbms_output.put_line('For clause: WHERE equipment_id = R.equipment_id OR (equipment_id IS NULL AND R.equipment_id IS NULL)');
     23    dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
     24    dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
     25  
     26  -- Form 2 of the where clause
     27    v_t1 := dbms_utility.get_time;
     28    v_c1 := dbms_utility.get_cpu_time;
     29    FOR R IN B LOOP
     30       SELECT COUNT(*)
     31         INTO v_b
     32         FROM batch
     33        WHERE NVL(equipment_id,'xxxx') = NVL(R.equipment_id,'xxxx');
     34    END LOOP;
     35    v_t2 := dbms_utility.get_time;
     36    v_c2 := dbms_utility.get_cpu_time;
     37    dbms_output.put_line('For clause: WHERE NVL(equipment_id,''xxxx'') = NVL(R.equipment_id,''xxxx'')');
     38    dbms_output.put_line('CPU seconds used: '||(v_c2 - v_c1)/100);
     39    dbms_output.put_line('Elapsed time: '||(v_t2 - v_t1)/100);
     40  END;
     41  /


    For clause: WHERE equipment_id = R.equipment_id OR (equipment_id IS NULL AND R.equipment_id IS NULL)
    CPU seconds used: 84.69
    Elapsed time: 84.8
    For clause: WHERE NVL(equipment_id,'xxxx') = NVL(R.equipment_id,'xxxx')
    CPU seconds used: 124
    Elapsed time: 124.01

    PL/SQL procedure successfully completed

    SQL> select count(*) from batch;

  COUNT(*)
----------
     20903

SQL> 
Run Code Online (Sandbox Code Playgroud)

我很惊讶地发现Andy是多么正确.NVL解决方案的成本要高出近50%.因此,即使一段代码看起来不像另一段代码那么整洁或优雅,但它可能效率更高.我多次运行此程序,每次结果几乎相同.感谢安迪......


Chr*_*fer 13

我不知道它是否更简单,但我偶尔也会使用

WHERE ISNULL(MyColumn, -1) = ISNULL(SearchValue, -1)
Run Code Online (Sandbox Code Playgroud)

将"-1"替换为对列类型有效但也不太可能在数据中实际找到的值.

注意:我使用的是MS SQL,而不是Oracle,所以不确定"ISNULL"是否有效.

  • 对于选择NULL替换值的建议标准,我并不完全满意."不太可能找到"的标准是否足够?当在平等测试的任何一方出现"不太可能"的值时会发生什么.现在可以将NULL与"不太可能"的值匹配吗? (5认同)
  • 如果任何一个值合法地为-1,那么就会分崩离析,然后你会拔出你的头发找到这个bug. (4认同)
  • 等效的 Oracle 函数是 NVL。相同的语法。 (2认同)

Pet*_*inl 13

Expert Oracle数据库架构中,我看到:

WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1
Run Code Online (Sandbox Code Playgroud)


Jos*_*ons 7

使用NVL将null替换为两侧的虚拟值,如下所示:

WHERE NVL(MYCOLUMN,0) = NVL(SEARCHVALUE,0)
Run Code Online (Sandbox Code Playgroud)

  • 您根本不需要使用此方法.当您可以直接与实际NULL进行比较时,没有理由与虚拟值进行比较. (4认同)
  • 如果数据或搜索值中可能出现0,则需要使用不同的虚拟值.如果您无法提出适当的虚拟值,则无法使用此方法. (3认同)

Vin*_*vic 5

另一种替代方案,从执行的查询角度来看可能是最佳的,只有在进行某种查询生成时才有用,它是根据搜索值生成所需的确切查询.

伪代码如下.

if (SEARCHVALUE IS NULL) {
    condition = 'MYCOLUMN IS NULL'
} else {
    condition = 'MYCOLUMN=SEARCHVALUE'
}
runQuery(query,condition)
Run Code Online (Sandbox Code Playgroud)