Получить null == null в SQL

Я хочу найти таблицу базы данных в столбце nullable. Иногда значение я искать сама нуль. Поскольку Null равен nothing, даже NULL, говоря

where MYCOLUMN=SEARCHVALUE 

не удастся. Прямо сейчас я должен прибегнуть к

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

есть ли более простой способ сказать это?

(Я использую Oracle, если это имеет значение)

11 ответов


вы можете делать вещи IsNull или NVL, но это просто заставит двигатель работать больше. Вы будете вызывать функции для преобразования столбцов, которые затем должны иметь результаты сравнения.

использовать то, что у вас есть

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

@Andy Lester утверждает, что исходная форма запроса более эффективна, чем использование NVL. Я решил проверить это утверждение:--2-->

    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> 

Я был немного удивлен, узнав, насколько прав Энди. Это стоит почти на 50% больше, чтобы сделать решение NVL. Таким образом, хотя один фрагмент кода может выглядеть не таким аккуратным или элегантным, как другой, он может быть значительно более эффективным. Я выполнял эту процедуру несколько раз, и результаты были почти одинаковыми каждый раз. Спасибо Энди...


на Экспертная Архитектура Базы Данных Oracle я увидел:

WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1

Я не знаю, проще ли это, но я иногда использовал


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

замена "-1" некоторым значением, которое допустимо для типа столбца, но также вряд ли будет найдено в данных.

примечание: Я использую MS SQL, а не Oracle, поэтому не уверен, что" ISNULL " допустим.


используйте NVL для замены null на некоторое фиктивное значение с обеих сторон, как в:

WHERE NVL(MYCOLUMN,0) = NVL(SEARCHVALUE,0)

другая альтернатива, которая, вероятно, оптимальна с точки зрения выполненного запроса, и будет полезно, только если вы делаете какой-то генерации запросов должен генерировать точный запрос, который вам нужен, на основе значения поиска.

псевдокоде следующим образом.

if (SEARCHVALUE IS NULL) {
    condition = 'MYCOLUMN IS NULL'
} else {
    condition = 'MYCOLUMN=SEARCHVALUE'
}
runQuery(query,condition)

Если возможно внеполосное значение:

where coalesce(mycolumn, 'out-of-band') 
    = coalesce(searchvalue, 'out-of-band')

Это также может сделать работу в Oracle.

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

есть некоторые ситуации, когда он бьет тест IS NULL с помощью OR.

Я также был удивлен, что DECODE позволяет проверять NULL против NULL.

WITH 
TEST AS
(
    SELECT NULL A FROM DUAL
)
SELECT DECODE (A, NULL, 'NULL IS EQUAL', 'NULL IS NOT EQUAL')
FROM TEST

попробовать

WHERE NVL(mycolumn,'NULL') = NVL(searchvalue,'NULL')

Я бы подумал, что у вас все в порядке. Вы могли бы использовать:

where NVL(MYCOLUMN, '') = NVL(SEARCHVALUE, '')

Это ситуация, в которой мы оказываемся во многом с нашими функциями 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)