Я вирішив проблему запиту, використовуючи ... row_number() over (partition by
... це більш загальне питання про те, чому ми не можемо використовувати стовпці з нульовими значеннями. Чому заради об’єднання нуль не може бути рівний нулю?
Я вирішив проблему запиту, використовуючи ... row_number() over (partition by
... це більш загальне питання про те, чому ми не можемо використовувати стовпці з нульовими значеннями. Чому заради об’єднання нуль не може бути рівний нулю?
Відповіді:
Чому заради об’єднання нуль не може бути рівний нулю?
Просто скажіть Oracle зробити це:
select *
from one t1
join two t2 on coalesce(t1.id, -1) = coalesce(t2.id, -1);
(Зауважте, що в стандартному SQL ви можете використовувати t1.id is not distinct from t2.id
для отримання безпечного оператора рівності, але Oracle цього не підтримує)
Але це буде працювати лише в тому випадку, якщо значення заміни (-1 у прикладі вище) насправді не відображається в таблиці. Знаходження такої «чарівної» значення для чисел може бути можливо, але це буде дуже важко для символьних значень (особливо тому , що Oracle обробляє порожній рядок , як null
і)
Плюс: індекс у id
стовпцях не буде використаний (ви можете визначити індекс на основі функції з coalesce()
виразом, хоча).
Ще один варіант, який працює для всіх типів, без магічних значень:
on t1.id = t2.id or (t1.id is null and t2.id is null)
Але справжнє питання: чи це має сенс?
Розглянемо наступні вибіркові дані:
Таблиця перша
id
----
1
2
(null)
(null)
Таблиця друга
id
----
1
2
(null)
(null)
(null)
Яку з комбінацій нульових значень слід обрати під час з'єднання? Мій вище приклад призведе до чогось на зразок перехресного з'єднання для всіх нульових значень.
T1_ID | T2_ID
-------+-------
1 | 1
2 | 2
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
(null) | (null)
Крім того, ви можете зробити два нулі одна одній, використовуючи INTERSECT
як оператор рівності:
SELECT
*
FROM
t1
INNER JOIN t2
ON EXISTS (SELECT t1.ID FROM DUAL INTERSECT SELECT t2.ID FROM DUAL)
;
Дивіться цю демонстрацію DBFiddle для ілюстрації.
Звичайно, це виглядає досить пишно, хоча насправді не набагато довше, ніж пропозиція BriteSponge . Однак це, безумовно, не відповідає, якщо ви помилуєте каламбур, на стислість згаданих раніше в коментарях стандартних способів, якими є IS NOT DISTINCT FROM
оператор, ще не підтримується в Oracle.
Просто для повноти зазначу, що функцію SYS_OP_MAP_NONNULL
тепер можна безпечно використовувати для порівняння значень, які є нульовими, як це тепер зафіксовано в документації 12c. Це означає, що Oracle не буде видаляти його випадковим чином і порушувати ваш код.
SELECT *
FROM one t1
JOIN two t2
ON SYS_OP_MAP_NONNULL(t1.id) = SYS_OP_MAP_NONNULL(t2.id)
Перевага полягає в тому, що ви не стикаєтеся з проблемою "магічного" числа.
Посилання в документах Oracle приведені в розділі Basic Materialized Views - Choice Indexes for Materialized Views .
Ви можете приєднати нульові значення за допомогою декодування:
on decode(t1.id, t2.id, 1, 0) = 1
decode
трактує нулі як рівні, тому це працює без "магічних" чисел. Два стовпці повинні мати однаковий тип даних.
Він не зробить найбільш читабельного коду, але, мабуть, все-таки краще, ніж t1.id = t2.id or (t1.id is null and t2.id is null)
Чому не можна використовувати нульові значення при приєднанні? В Oracle обидва з перерахованих нижче не оцінюють справжнє:
NULL = NULL
NULL <> NULL
Ось чому ми маємо IS NULL
/ IS NOT NULL
перевірити наявність нульових значень.
Щоб перевірити це, ви можете просто зробити:
SELECT * FROM table_name WHERE NULL = NULL
Приєднання оцінюють булевий стан, і вони не запрограмували їх працювати інакше. Ви можете поставити знак, що перевищує значення, ніж умову приєднання, та додати інші умови; він просто оцінює це як булевий вираз.
Я думаю, що нуль не може бути рівним нулю в з'єднанні заради послідовності. Це б заперечувало звичайну поведінку оператора порівняння.
NULL = anything
призводить до того, NULL
що стандарт SQL так говорить. Рядок задовольняє умові приєднання, лише якщо вираз є істинним.
Нульове значення в більшості реляційних баз даних вважається НЕЗАЄМО. Це не слід плутати з усіма нулями HEX. якщо щось містить null (невідомо,), ви не можете його порівняти.
Unknown = Known False
Unknown = Unknown False
Unknown >= Known False
Known >= Unknown False
Що означає, що коли ви матимете нуль як операнда в бульному виразі, інша частина завжди буде правдою.
На відміну від загальної ненависті розробників до нуля, null має своє місце. Якщо щось невідоме, використовуйте null.
UNKNOWN
, ні FALSE
;)
where (a = b or (a is null and b is null))
період. Це мої думки щодо цього. Я б не розглядав питання використанняsys_op_map_nonnull
, ігнорував би цю людину за завісою ".