2015-12-10 2 views
0

Я пытаюсь выяснить, самый простой обобщенный выражение SQL, который может проверить, если две колонки a и b одинаковы. Другими словами, выражение, которое вычисляется в true, когда:выражение Простейшее SQL, чтобы проверить, если два столбца имеют одинаковое значение для учета NULL

  1. a является NULL и b является NULL; или
  2. a не NULL и b не NULL и a = b

Пусть столбцы a и b имеют точно такой же тип данных.

Наиболее очевидное решение, которое я использую в примере ниже, это ужасно запутанным, особенно потому, что мне нужно повторить этот пункт 15x в 15 столбцов таблицы:

SELECT * FROM (

    SELECT 'x' a, 'x' b FROM dual 
     UNION ALL 
    SELECT 'x' a, NULL b FROM dual 
     UNION ALL 
    SELECT NULL a, 'x' b FROM dual 
     UNION ALL 
    SELECT NULL a, NULL b FROM dual 
     UNION ALL 
    SELECT 'x' a, 'y' b FROM dual 
     UNION ALL 
    SELECT 'x' a, NULL b FROM dual 
     UNION ALL 
    SELECT NULL a, 'y' b FROM dual 
     UNION ALL 
    SELECT NULL a, NULL b FROM dual 

) 

WHERE (a IS NULL AND b IS NULL) OR 
     (a IS NOT NULL AND b IS NOT NULL AND a = b) 
/

и ожидаемый результат является:

+--------+--------+ 
| a | b | 
+--------+--------+ 
| x  | x  | 
| (null) | (null) | 
| (null) | (null) | 
+--------+--------+ 

Т.Л., др - Могу ли я упростить мою статью WHERE, т.е. сделать его более компактным, сохраняя при этом его логически правильно?

P.S .: Я не мог наплевать на любые попытки пуриста SQL, что «NULL не является значением». Для моих практических целей, если a содержит NULL и b не делают, то aотличаются от b. Они не «неизвестны», отличаются ли они. Поэтому, пожалуйста, заранее, никаких аргументов в этой переулке!

P.P.S .: Мой вкус SQL - это Oracle 11g.

PPPS: Кто-то решил, что этот вопрос является дубликатом «Is there better Oracle operator to do null-safe equality check?», но беглая проверка в этом вопросе будет показано, что ответы на них менее полезны, чем те, которые размещен на эту тему и не удовлетворяют моего частности, и explicitly- заявленные критерии. Просто потому, что они похожи, они не дублируют их. Я никогда не понимал, почему люди на SO так усердно работают, чтобы заставить мою проблему X быть чужой проблемой. Y.

+0

Я обычно использую функцию 'ISNULL()' в SQL Server, я думаю, что 'NVL()' эквивалентен в Oracle, может быть, попытаться взглянуть на эту функцию? – xbb

+0

NVL() не работает. LNNVL должен работать. – EvilTeach

+1

'LNNVL' в этом дублирующем вопросе именно то, что вы ищете. – Noel

ответ

0

Простой не обязательно исполнитель.

рассмотрите эту возможность.

WHERE X || 'x' = Y || 'x' 

Если вы хотите, чтобы действительно подтолкнуть конверт, используйте SYS_OP_MAP_NONNULL

+0

Меня не интересует исполнитель. Меня касается только компактность выражения. – 0xbe5077ed

+0

Интересно. Каково состояние бизнеса, которое вызывает беспокойство? – EvilTeach

+0

Компактность и читаемость кода? Общий уклон к тому, чтобы быть простым и кратким, а не подробным и невозможным для чтения. И я думаю, что вы можете смело предположить, так как я сказал, что компактность - это цель, которую я знаю достаточно о данных, которые я имею в виду, чтобы знать выполнение предложения WHERE, просто не имеет большого значения. – 0xbe5077ed

2

Вы можете легко упростить как:

WHERE (a IS NULL AND b IS NULL) OR 
     (a = b) 

IS NOT NULL не требуется.

Если у вас есть «безопасное» значение (т.один, который никогда не используется), вы можете сделать это:

WHERE COALESCE(a, ' ') = COALESCE(b, ' ') 

Это предполагает, что ' ' не является допустимым значением.

+0

Первый, безусловно, лучше. Я не понял, что [таблица истинности для ИСТИННОГО ИЛИ НЕИЗВЕСТНОГО] (https://docs.oracle.com/cd/B19306_01/server.102/b14200/conditions004.htm#sthref2753) создала TRUE. Однако у меня нет надежной ценности для использования с «COALESCE». – 0xbe5077ed

1

Я нашел статью Ask "Safely Comparing NULL Columns As Equal", чтобы быть наиболее полезной. В Oracle, вы можете использовать функцию DECODE, чтобы сделать это:

WHERE 1 = DECODE(a, b, 1, 0) 

И это самое компактное решение, которое я видел до сих пор.

-1
SELECT * FROM (

SELECT 'x' a, 'x' b FROM dual 
    UNION ALL 
SELECT 'x' a, NULL b FROM dual 
    UNION ALL 
SELECT NULL a, 'x' b FROM dual 
    UNION ALL 
SELECT NULL a, NULL b FROM dual 
    UNION ALL 
SELECT 'x' a, 'y' b FROM dual 
    UNION ALL 
SELECT 'x' a, NULL b FROM dual 
    UNION ALL 
SELECT NULL a, 'y' b FROM dual 
    UNION ALL 
SELECT NULL a, NULL b FROM dual 

) 

WHERE NVL(a,'1')=NVL(b,'1') 
+0

Хотя «1» не в моем наборе данных примера, вы можете легко представить, что это может быть в реальном наборе данных. Я хотел бы решение, которое не требует, чтобы данное значение не появилось в наборе данных. См. Мой комментарий к ответу @Gordon Linoff ниже: «Однако у меня нет безопасной ценности для использования с COALESCE». – 0xbe5077ed

+0

Вы можете заменить '1' тем, что никогда не появится в вашем наборе данных (это могут быть «xxxxx» или «aaaaa» или что-то еще) –