#oracle
#Oracle
Вопрос:
Я работал со сложным представлением, написанным какой-то другой компанией в 2005 году. Я пытаюсь понять, что он делает по причинам, выходящим за рамки этого поста. Из-за чрезвычайно сложной природы этого представления (более 500 строк кода) Я так понимаю, что авторы обновляют то, что они делают.
Я продолжаю находить такие вещи, как TO_NUMBER (null), TO_DATE (null) в разных местах.
Мне кажется, что совершенно ненужное использование функции. Есть ли какие-либо технические причины или преимущества, которые оправдывают, почему это был такой дизайн?
Комментарии:
1. Я предполагаю, что это используется, чтобы заставить столбец, который равен null, иметь определенный тип данных. Использование just
null
не гарантирует тип, если я не ошибаюсь2. Это похоже на то, как человек хлопает в ладоши каждые несколько секунд, чтобы отогнать слонов. Когда вы указываете, что здесь нет слонов, он просто говорит: «Смотрите, это работает!» Этот код решает проблемы, которых изначально не существовало. Это суеверие.
Ответ №1:
По умолчанию NULL не имеет типа данных:
SQL> select dump(null) from dual;
DUMP
----
NULL
SQL>
Однако, если мы заставим Oracle принять решение, по умолчанию оно будет преобразовано в строку:
SQL> create or replace view v1 as
select 1 as id
, null as dt
from dual
/
2 3 4 5
View created.
SQL> desc v1
Name Null? Type
-------------- -------- ----------------------------
ID NUMBER
DT VARCHAR2
SQL>
Но это не всегда желательно. Возможно, нам потребуется использовать NULL в представлении по ряду причин (определение API, заполнение неровного ОБЪЕДИНЕНИЯ и т.д.), И поэтому мы приводим NULL к другому типу данных, чтобы получить нужную нам проекцию.
SQL> create or replace view v1 as
select 1 as id
, to_date(null) as dt
from dual
/
2 3 4 5
View created.
SQL> desc v1
Name Null? Type
-------------- -------- ----------------------------
ID NUMBER
DT DATE
SQL>
Более поздние версии стали умнее в отношении обработки ОБЪЕДИНЕНИЯ. В моей базе данных 11gR2, несмотря на то, что я использую null в первом объявленном запросе (и это обычно приводит к сбоям) Я все еще получаю правильный тип данных:
SQL> create or replace view v1 as
select 1 as id
, null as dt
from dual
union all
select 2 as id
, sysdate as something_else
from dual
/
2 3 4 5 6 7 8 9
View created.
SQL>
SQL> desc v1
Name Null? Type
-------------- -------- ----------------------------
ID NUMBER
DT DATE
SQL>
Ответ №2:
Явное приведение NULL
может быть перенесено с 8i или для обхода ошибки, или, как сказал ammoQ, «суеверный».
В некоторых старых и редких случаях неявное преобразование NULL
в операциях set вызывало ошибки типа ORA-01790: expression must have same datatype as corresponding expression
. Я не могу найти никаких хороших ссылок на это старое поведение, но Google возвращает несколько результатов, в которых утверждается, что подобный запрос завершится ошибкой в 8i:
select 'a' a from dual
union
select null a from dual;
И есть по крайней мере одна похожая ошибка: «Ошибка 9456979, неправильный результат из-за отправки NVL / DECODE в представление ОБЪЕДИНЕНИЯ с замененным элементом списка выбора NULL».
Но не позволяйте 16-летнему программному обеспечению и какой-нибудь редкой ошибке указывать, как программировать. И не думаю, что существует положительная корреляция между навыками программирования размера кода. Существует отрицательная корреляция: хорошие программисты будут создавать меньший по размеру, более читаемый код и не оставят столько загадок для будущих программистов.
Комментарии:
1. Я думаю, вы, возможно, на правильном пути. Ваш пример объединения точно показывает, как он использовался. Я также согласен с вами в отрицательной корреляции между размером кода и навыками программирования. Потратив целый день на обратный инжиниринг этого монстра, я должен сказать, что было бы эффективнее, если бы он был разбит на более мелкие, более управляемые компоненты.
Ответ №3:
Ну, я бы предпочел CAST(NULL AS DATE)
или CAST(NULL AS NUMBER)
вместо TO_DATA(NULL)
, на мой взгляд, выглядит более логично.
Я знаю два сценария, в которых требуется такое выражение. Один из них — это случай ОБЪЕДИНЕНИЯ, как уже указывалось в других ответах.
Другой сценарий — это случай перегруженных процедур / функций, например:
CREATE OR REPLACE PROCEDURE MY_PROC(val IN DATE) AS
BEGIN
DELETE FROM EMP WHERE HIRE_DATE = val;
END;
/
CREATE OR REPLACE PROCEDURE MY_PROC(val IN NUMBER) AS
BEGIN
DELETE FROM EMP WHERE EMP_ID = val;
END;
/
Вызов процедуры, подобной MY_PROC(NULL);
, не работает, Oracle не знает, какую процедуру выполнить. Вы должны вызвать это как MY_PROC(CAST(NULL AS DATE));
, например.
Ответ №4:
Как программист Oracle PL / SQL, я действительно не нахожу никакой логической причины для выполнения указанных вами действий. Единственный логичный подход, с которым можно справиться null
в oracle, — это использовать nvl()
, я действительно не нахожу никаких причин использовать TO_NUMBER(null)
, TO_DATE(null)
в сложном представлении.