Oracle, нужна помощь в понимании функций to_number и to_date

#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) в сложном представлении.