我希望在可空列上搜索数据库表.有时我搜索的值本身就是NULL.因为Null等于什么,甚至是NULL,说
where MYCOLUMN=SEARCHVALUE
将失败.现在我不得不诉诸
where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
有更简单的说法吗?
(如果重要,我正在使用Oracle)
你可以做IsNull或NVL的东西,但它只是让引擎做更多工作.您将调用函数来进行列转换,然后必须比较结果.
用你拥有的
where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
@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>
我很惊讶地发现Andy是多么正确.NVL解决方案的成本要高出近50%.因此,即使一段代码看起来不像另一段代码那么整洁或优雅,但它可能效率更高.我多次运行此程序,每次结果几乎相同.感谢安迪......
我不知道它是否更简单,但我偶尔也会使用
WHERE ISNULL(MyColumn, -1) = ISNULL(SearchValue, -1)
将"-1"替换为对列类型有效但也不太可能在数据中实际找到的值.
注意:我使用的是MS SQL,而不是Oracle,所以不确定"ISNULL"是否有效.
在Expert Oracle数据库架构中,我看到:
WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1
使用NVL将null替换为两侧的虚拟值,如下所示:
WHERE NVL(MYCOLUMN,0) = NVL(SEARCHVALUE,0)
另一种替代方案,从执行的查询角度来看可能是最佳的,只有在进行某种查询生成时才有用,它是根据搜索值生成所需的确切查询.
伪代码如下.
if (SEARCHVALUE IS NULL) { condition = 'MYCOLUMN IS NULL' } else { condition = 'MYCOLUMN=SEARCHVALUE' } runQuery(query,condition)