Определить Oracle null == null

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

where MYCOLUMN=SEARCHVALUE 

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

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

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

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

Совершенно очевидно, что NVL «замедлит работу», особенно для индексированных столбцов.

AnBisw 11.08.2012 01:06
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
45
1
25 150
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Пытаться

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

что произойдет, если mycolumn имеет значение NULL, а значение searchvalue равно NULL; или наоборот?

dlamblin 10.10.2008 18:51

Решение этого комментария оставлено читателю в качестве упражнения ;-)

DCookie 10.10.2008 19:06

Я не получил голосов против. Ответ неверный? Если да, то любезно изложите свои возражения. Возможно, я мог бы скорректировать свой ответ, чтобы обратиться к ним. Что касается первоначального комментария, то это была концептуальная иллюстрация. Я думал, что было довольно ясно, что нужно использовать значение, которое не будет отображаться в ваших данных ...

DCookie 14.12.2010 19:10

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

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

что произойдет, если значение mycolumn равно нулю, а значение поиска равно 0; или наоборот?

dlamblin 10.10.2008 18:48

Если 0 - это что-то, что может встречаться в ваших данных или в поисковом значении, вам нужно использовать другое фиктивное значение. Если вы не можете найти подходящее фиктивное значение, вы не можете использовать этот подход.

Dave Costa 10.10.2008 18:52

Вам вообще не нужно использовать этот подход. Нет причин сравнивать с фиктивными значениями, когда вы можете напрямую сравнивать с фактическим NULL.

Andy Lester 09.10.2009 23:53

Не знаю, проще ли, но иногда использовал

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

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

ПРИМЕЧАНИЕ. Я использую MS SQL, а не Oracle, поэтому не уверен, действительно ли ISNULL.

Эквивалентная функция Oracle - NVL. Тот же синтаксис.

JosephStyons 10.10.2008 18:42

Кстати, вы можете сделать то же самое с Coalesce (MyColumn, -1) = Coalesce (SearchValue, -1).

Craig 10.10.2008 18:59

Меня не совсем устраивают предлагаемые критерии выбора значения замены NULL. Достаточно ли критерия «вряд ли будет найдено»? Что происходит, когда по обе стороны от теста на равенство появляется «маловероятное» значение. Приемлемо ли теперь сопоставить NULL с «маловероятным» значением?

spencer7593 29.05.2009 07:03

Это развалится, если любое из значений может на законных основаниях быть -1, и тогда вы будете выдергивать волосы, чтобы найти ошибку.

Andy Lester 09.10.2009 23:53
Ответ принят как подходящий

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

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

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

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

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

Это не сработает, потому что пустая строка эквивалентна NULL в Oracle, что возвращает нас к тому же сравнению NULL == NULL.

Erick B 20.10.2008 22:24

Черт, теперь я вспомнил эту маленькую глупость! Я думаю, что оставлю этот ответ как напоминание всем остальным

Carl 21.10.2008 12:24

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

Далее следует псевдокод.

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

за исключением того, что вы должны использовать переменную привязки!

Dave Costa 10.10.2008 18:54

Я не думаю, что вы могли бы использовать здесь переменную привязки, не нарушая свою цель

user533832 02.05.2011 14:35

@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% дороже. Таким образом, даже если один фрагмент кода может выглядеть не так аккуратно или элегантно, как другой, он может быть значительно более эффективным. Я запускал эту процедуру несколько раз, и каждый раз результаты были почти одинаковыми. Престижность Энди ...

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

James Curran 10.10.2008 20:15

Также учтите, что выполнение этих преобразований означает, что движок не может использовать индекс, если он есть в столбце. Например, вот так: где? = foo + 1 не может использовать индекс для foo, но где? - 1 = foo может использовать индекс. Вы часто будете сталкиваться с этим с указателями даты.

Andy Lester 10.10.2008 22:19

Вот тест Тома: asktom.oracle.com/pls/asktom/…

Vadzim 10.10.2016 21:23

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

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

В стандартном SQL конкатенация с NULL дает NULL, поэтому вы получите NULL = NULL, что неверно. Позволяет ли Oracle этому работать?

Jonathan Leffler 09.12.2008 05:49

Я успешно использовал это в оракуле.

EvilTeach 10.12.2008 05:54

Я бы хотел изменить свой голос против (извините за поспешность) на голос за, чего я не могу сделать, пока вы не отредактируете свой ответ. Было бы неплохо добавить примечание о типах данных MYCOLUMN и SEARCHVALUE - работает ли это для всех символьных типов данных, всех числовых? любой другой?

user533832 02.05.2011 14:31

@Джек. Я не проводил формального расследования всех типов данных. Я использовал его с VARCHAR2, поэтому в худшем случае вы можете преобразовать его в VARCHAR2.

EvilTeach 02.05.2011 19:31

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

WHERE DECODE(MYCOLUMN, SEARCHVALUE, 1) = 1

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

Другие вопросы по теме