46

我希望在可为空的列上搜索数据库表。有时我要搜索的值本身就是 NULL。由于 Null 等于无,甚至 NULL,说

where MYCOLUMN=SEARCHVALUE 

将失败。现在我不得不求助于

where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))

有没有更简单的说法?

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

4

11 回答 11

72

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

使用你所拥有的

where ((MYCOLUMN=SEARCHVALUE) OR (MYCOLUMN is NULL and SEARCHVALUE is NULL))
于 2008-10-10T14:42:06.330 回答
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> 

我有点惊讶地发现安迪是多么正确。做 NVL 解决方案的成本要高出近 50%。因此,即使一段代码可能看起来不像另一段代码那样整洁或优雅,但它的效率可能会显着提高。我多次运行此程序,每次结果几乎相同。向安迪致敬...

于 2008-10-10T16:12:03.653 回答
14

Expert Oracle Database Architecture中,我看到:

WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1
于 2011-03-14T20:17:55.947 回答
13

不知道是不是更简单,但我偶尔用过

WHERE ISNULL(MyColumn, -1) = ISNULL(SearchValue, -1)

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

注意:我使用 MS SQL,而不是 Oracle,所以不确定“ISNULL”是否有效。

于 2008-10-10T14:40:11.500 回答
8

使用 NVL 在两边用一些虚拟值替换 null,如下所示:

WHERE NVL(MYCOLUMN,0) = NVL(SEARCHVALUE,0)
于 2008-10-10T14:40:10.063 回答
6

另一种选择,从执行查询的角度来看可能是最佳的,并且仅在您进行某种查询生成时才有用,即根据搜索值生成您需要的确切查询。

伪代码如下。

if (SEARCHVALUE IS NULL) {
    condition = 'MYCOLUMN IS NULL'
} else {
    condition = 'MYCOLUMN=SEARCHVALUE'
}
runQuery(query,condition)
于 2008-10-10T14:46:10.427 回答
2

尝试

WHERE NVL(mycolumn,'NULL') = NVL(searchvalue,'NULL')
于 2008-10-10T14:39:52.967 回答
2

如果带外值是可能的:

where coalesce(mycolumn, 'out-of-band') 
    = coalesce(searchvalue, 'out-of-band')
于 2008-11-09T10:07:29.980 回答
1

这也可以在 Oracle 中完成。

WHERE MYCOLUMN || 'X'  = SEARCHVALUE || 'X'

在某些情况下,它通过 OR 击败了 IS NULL 测试。

我也很惊讶 DECODE 可以让你检查 NULL 和 NULL。

WITH 
TEST AS
(
    SELECT NULL A FROM DUAL
)
SELECT DECODE (A, NULL, 'NULL IS EQUAL', 'NULL IS NOT EQUAL')
FROM TEST
于 2008-12-09T02:30:07.890 回答
0

我认为你所拥有的还可以。你也许可以使用:

where NVL(MYCOLUMN, '') = NVL(SEARCHVALUE, '')
于 2008-10-10T14:42:25.863 回答
0

使用驱动报告的 Oracle 功能,我们经常遇到这种情况。我们希望允许用户输入一个值来限制结果或将其留空以返回所有记录。这是我用过的,对我们来说效果很好。

WHERE rte_pending.ltr_rte_id = prte_id
  OR ((rte_pending.ltr_rte_id IS NULL OR rte_pending.ltr_rte_id IS NOT NULL)
      AND prte_id IS NULL)
于 2013-06-06T12:08:19.047 回答