Подтвердить что ты не робот

SQL "Присоединиться" к нулевым значениям

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

SELECT * FROM T1 JOIN T2 ON nvl(T1.SOMECOL,'f44087d5935dccbda23f71f3e9beb491') = 
   nvl(T2.SOMECOL,'f44087d5935dccbda23f71f3e9beb491')

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

Изменить: Чтобы быть ясным, я не только обеспокоен нулями. Если столбцы не равны нулю, я хочу, чтобы они соответствовали их фактическим значениям.

4b9b3361

Ответ 1

Возможно, это сработает, но я никогда не пробовал:

SELECT * 
FROM T1 JOIN T2 
ON T1.SOMECOL = T2.SOMECOL OR (T1.SOMECOL IS NULL AND T2.SOMECOL IS NULL)

Ответ 2

В SQL Server я использовал:

WHERE (a.col = b.col OR COALESCE(a.col, b.col) IS NULL)

Очевидно, что неэффективно из-за OR, но если нет зарезервированного значения, вы можете сопоставлять NULL с обеих сторон без двусмысленности или сгибания, что самое лучшее, что вы можете сделать (и если было, почему NULL даже разрешен в вашем дизайн...)

Ответ 3

Вы не можете сделать ничего лучше, но JOIN, который у вас есть, не будет делать фактического "JOIN" каким-либо образом (между T1.SOMECOL и T2.SOMECOL не будет никакой корреляции, кроме как у них есть NULL значение для этого столбца). В основном это означает, что вы не сможете использовать JOIN на NULL, чтобы увидеть, соответствуют ли строки.

NULL никогда не равен другому NULL. Как может что-то неизвестное значение быть равно другому неизвестному значению?

Ответ 4

Для такого рода задач Oracle внутренне использует недокументированную функцию sys_op_map_nonnull(), где ваш запрос будет выглядеть следующим образом:

SELECT *
FROM T1 JOIN T2 ON sys_op_map_nonnull(T1.SOMECOL) = sys_op_map_nonnull(T2.SOMECOL)

Недокументированные, поэтому будьте осторожны, если вы идете по этому маршруту.

Ответ 5

Простой, используйте COALESCE, который вернет свой первый ненулевой параметр:

SELECT * FROM T1 JOIN T2 ON 
  COALESCE(T1.Field, 'magic string') = 
     COALESCE(T2.Field, 'magic string')

Единственное, о чем вам придется беспокоиться, это то, что "волшебная строка" не может быть среди юридических значений для поля объединения в любой таблице.

Ответ 6

Вы действительно хотите иметь возможность присоединиться к таблицам, если значение равно null? Не можете ли вы просто исключить возможные значения NULL в предикат соединения? Мне трудно понять, что строки в двух таблицах могут быть связаны нулевым значением. Если у вас 100 нулей в table1.col_a и 100 нулей в таблице2.col_b, у вас будет 10000 строк, возвращаемых только для строк с нулевым значением. Звучит неправильно.

Однако вы сказали, что вам это нужно. Могу ли я предложить объединить нулевой столбец в меньшую строку, поскольку сравнение символов относительно дорого. Еще лучше объединить нули в целое число, если данные в столбцах будут текстовыми. Затем у вас очень быстрые "сравнения", и вы вряд ли столкнетесь с существующими данными.

Ответ 7

Просто выбросив это - есть ли способ объединить эти значения в известное значение, например пустую строку? Не зная о том, как выкладывается ваша таблица, означает, что я не могу быть уверен, что вы потеряете смысл таким образом - то есть, если пустая строка представляет "пользователь отказался ввести номер телефона", а NULL - "мы забыли" спросить об этом "или что-то в этом роде?

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

Ответ 8

Разве это не совпадает с проверкой наличия нулей в обоих столбцах?

SELECT * FROM T1, T2 WHERE T1.SOMECOL IS NULL and T2.SOMECOL IS NULL

или

SELECT * FROM T1 CROSS JOIN T2 WHERE T1.SOMECOL IS NULL and T2.SOMECOL IS NULL

Ответ 9

Почему бы не что-то подобное:

SELECT * FROM T1 JOIN T2 ON nvl (T1.SOMECOL, 'null') =  NVL (T2.SOMECOL, 'нулевой')

Я не знаю, почему вы используете UUID. Вы можете использовать любую строку, отсутствующую в столбцах, например, строку "null", например, для уменьшения объема памяти. И решение, использующее nvl, намного быстрее, чем решение, использующее or ... is null, предложенное Эриком Петроелем, например.

Ответ 10

Вы можете попробовать использовать этот запрос ниже.

SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,0);

Ответ 11

Я думаю, вы все равно могли бы использовать nvl() для соединения:

SELECT *
FROM T1
JOIN T2 ON NVL(T2.COL1,-1)=NVL(T1.COL1,-1);

Но вам нужно будет добавить индексы на основе столбцов col1

CREATE INDEX IND_1 ON T1 (NVL(COL1,-1));
CREATE INDEX IND_2 ON T2 (NVL(COL1,-1));

Индексы должны значительно увеличить скорость соединения на NVL (..).

Ответ 12

Вы можете объединить нулевые значения, используя decode:

    SELECT * FROM T1 JOIN T2 ON DECODE(T1.SOMECOL, T2.SOMECOL, 1, 0) = 1

decode рассматривает нули как равные, поэтому это работает без "магических" чисел. Два столбца должны иметь одинаковый тип данных.

Это не сделает наиболее читаемый код, но, вероятно, все еще лучше, чем t1.id = t2.id or (t1.id is null and t2.id is null)

Ответ 13

@Сарат Аванаву

Этот не лучший подход. Если TA.COL1 сохраняет значение 0, а TB.COL2 равен NULL, он присоединится к этим записям, что неверно.

SELECT *
FROM TABLEA TA
JOIN TABLEB TB ON NVL(TA.COL1,0)=NVL(TB.COL2,0);

Ответ 14

Вы также можете использовать CASE для замены нулевого значения в подзапросах, затем СОЕДИНЯТЬ результаты:

SELECT T1.COL1 FROM
(
   (SELECT (CASE WHEN COL1 IS NULL THEN 'X' ELSE COL1 END) AS COL1 FROM TABLE1) T1
   JOIN
   (SELECT (CASE WHEN COL1 IS NULL THEN 'X' ELSE COL1 END) AS COL1 FROM TABLE2) T2
)
ON T1.COL1=T2.COL1