Тони Эндрюс в другом вопрос дал пример:
IF p_c_courtesies_cd
|| p_c_language_cd
|| v_c_name
|| v_c_firstname
|| v_c_function
|| p_c_phone
|| p_c_mobile p_c_fax
|| v_c_email is not null
THEN
-- Do something
END IF;
в качестве умной (если не малопонятной) альтернативы функции Oracle COALESCE. Конечно, это работает, если какой-либо аргумент не равен нулю, проверка IF верна. Мой вопрос: соответствует ли реализация Oracle указанной выше операции конкатенации SQL-92? Разве выражение, содержащее NULL, не должно оцениваться как NULL? Если вы так не думаете, то почему выражение 1 + NULL должно оцениваться как NULL?


Ну, COALESCE явно определен стандартом SQL-92 для возврата первого ненулевого значения в списке; так что по определению реализация этого Oracle работает правильно.
Обновлено: Спецификация SQL-92; найдите COALESCE, чтобы увидеть его определение.
Тем не менее, в NULL нет ничего особенного, что заявляет, что любая операция, связанная с NULL, должна быть NULL. Более точное ограничение состоит в том, что NULL не является ни ложным, ни 0, ни равным другому NULL (например, NULL == NULL является ложным, потому что один NULL не равен другому NULL). Однако это не означает, что не может быть логически согласованных способов работы с NULL, которые не всегда возвращают NULL.
Обновлено: Итак, NULL + 1 равно NULL так же, как NaN + 1 по-прежнему NaN; это фактически неопределенная операция.
@DCookie: а, я думал, вы спрашиваете, соответствует ли реализация COALESCE стандарту. Однако я согласен, их реализация CONCATENATION НЕ соответствует стандарту, если для этого она возвращает не NULL.
Извините за то, что не разобрался, я предполагаю, что из приведенного мной примера я имел в виду операцию конкатенации :-(
Нет, наверное, в этом есть смысл, уверен, я просто просмотрел это слишком быстро :)
SQL> select 'something'||null from dual;
'SOMETHIN
---------
something
конкатенация строки с нулем не приводит к нулю. Считаю это нормальным поведением, привык. Не знаю, что еще сказать.
Тот факт, что Oracle реализовал это таким образом, не означает, что это правильно.
Что-то правильно, когда все работает так, как описано в руководствах.
Например, Oracle, приравнивающий пустую строку к NULL, многие не считают правильным.
Я спрашиваю, соответствует ли он стандарту SQL. Извините, если это было непонятно.
Я не знаю, соответствует ли он стандарту SQL.
Добавлю, что PostgreSQL ведет себя стандартно: «SELECT 'something' || NULL;» возвращает NULL.
И MSSQL тоже ведет себя стандартно, даже несмотря на то, что они специально используют оператор «конкатенации строк»: «SELECT 'something' + NULL;» возвращает NULL.
@Nezroy: Спасибо за ссылку. Однако, читая стандарт, я считаю, что в нем говорится, что реализация Oracle на самом деле неверна. Раздел 6.13, Общие правила, пункт 2а:
2) If <concatenation> is specified, then let S1 and S2 be the re-
sult of the <character value expression> and <character factor>,
respectively.
Case:
a) If either S1 or S2 is the null value, then the result of the
<concatenation> is the null value.
Сначала я подумал, что вы спрашиваете, соответствует ли реализация COALESCE стандарту. Однако я согласен, их реализация CONCATENATION НЕ соответствует стандарту, если для этого она возвращает не NULL.
Да, мой вопрос был не совсем ясным. Мои извинения. По крайней мере, я знал, что я имел в виду ;-)
Основываясь на части спецификации SQL-92, выделенной DCookie, и поведении других БД, я бы сказал, что Oracle не ведет себя в соответствии со стандартом с их оператором конкатенации.
Oracle (из ответа Tuinstoel):
SQL> select 'something'||null from dual;
'SOMETHIN
---------
somethingMSSQL:
SELECT 'something'+NULL;
NULLPostgreSQL:
postgres=# \pset null '(null)'
Null display is "(null)".
postgres=# select 'something'||null as output;
output
--------
(null)
(1 row)
MySQL:
mysql> select concat('something',NULL) as output;
+--------+
| output |
+--------+
| NULL |
+--------+
1 row in set (0.00 sec)
Нет, подход Oracle к нулевым значениям идиосинкразичен, отличается от всех остальных и несовместим со стандартами ANSI. Однако в защиту Oracle он, вероятно, остановился и был привержен этому подходу задолго до того, как появился стандарт ANSI, которому следовало бы соответствовать!
Все начинается с того, что Oracle хранит строки со счетчиком символов, за которым следуют строковые данные. NULL представлен нулевым количеством символов без следующих строковых данных - что в точности совпадает с пустой строкой (''). Oracle просто не умеет их различать.
Это приводит к некоторому необычному поведению, например к этому случаю объединения. Oracle также имеет функцию LENGTH для возврата длины строки, но это было определено противоположным образом, так что LENGTH ('') возвращает NULL, а не ноль. Так:
LENGTH('abc') + LENGTH('') IS NULL
LENGTH('abc' || '') = 3
что, как мне кажется, нарушает основные математические принципы.
Конечно, разработчики Oracle настолько привыкли к этому, что многие из нас даже не видят в этом ничего неправильного или странного - некоторые на самом деле будут утверждать, что остальной мир неправ и что пустая строка и NULL находятся - одно и то же. вещь!
+1 за ссылку. Однако в стандарте, как я его читал, явно указывается, что результат конкатенации нулевого значения с чем-либо должен быть нулевым.