Oracle. CAST COLLECT для типа данных даты - PullRequest
0 голосов
/ 09 ноября 2018

Рассмотрим типы:

CREATE OR REPLACE   TYPE date_array AS  TABLE OF DATE; 
CREATE OR REPLACE   TYPE number_array AS  TABLE OF NUMBER;
CREATE OR REPLACE   TYPE char_array AS  TABLE OF VARCHAR2(80);

Запросы:

WITH q AS
 (SELECT LEVEL ID,
         TRUNC(SYSDATE) + LEVEL MyDate,
         to_char(LEVEL) STRING
  FROM   dual
  CONNECT BY LEVEL < 5)
SELECT CAST(COLLECT(ID) AS number_array)
FROM   q;

возврат коллекции чисел

WITH q AS
 (SELECT LEVEL ID,
         TRUNC(SYSDATE) + LEVEL MyDate,
         to_char(LEVEL) STRING
  FROM   dual
  CONNECT BY LEVEL < 5)
SELECT CAST(COLLECT(STRING) AS char_array)
FROM   q;

возврат коллекции строк

WITH q AS
 (SELECT LEVEL ID,
         TRUNC(SYSDATE) + LEVEL MyDate,
         to_char(LEVEL) STRING
  FROM   dual
  CONNECT BY LEVEL < 5)
SELECT CAST(COLLECT(MyDate) AS date_array)
FROM   q

ошибка возврата invalid datatype.

Может кто-нибудь объяснить, почему тип данных Date ведет себя по-разному?

1 Ответ

0 голосов
/ 09 ноября 2018

Вот мои выводы ... кажется, что вы столкнулись с ошибкой, вызванной тем фактом, что рассчитанные даты, по-видимому, имеют внутреннее представление, отличное от дат "базы данных". Я нашел обходной путь, так что продолжайте читать.

В моей установке oracle dev (Oracle 11g Enterprise Edition, выпуск 11.2.0.4.0 - 64-битная версия) у меня возникла та же проблема.

НО ... Если я создаю физическую таблицу, содержащую ваши тестовые данные:

create table test_data as 
SELECT LEVEL ID,
       TRUNC(SYSDATE) + LEVEL MyDate,
       to_char(LEVEL) STRING
FROM   dual
CONNECT BY LEVEL < 5

и затем запустите оператор «cast cast» для этой физической таблицы, он работает как положено:

-- this one works perfectly
SELECT CAST(COLLECT(MyDate) AS date_array) from test_data

но все эти примеры по-прежнему НЕ работают:

-- here I just added 1 .. and it doesn't work
SELECT CAST(COLLECT(MyDate + 1) AS date_array) 
from test_data

-- here I am extracting sysdate, instead of a physical column... and it doesn't work
SELECT CAST(COLLECT(sysdate) AS date_array) 
from test_data

Такое ощущение, что оракул не думает, что вычисленные даты - это то же самое, что и физические даты

Итак, я попытался «убедить» оракула, что данные, которые я предоставляю, на самом деле являются обычным значением DATE, используя явное приведение ... и EUREKA! это делает работу правильно:

  WITH q AS
  (SELECT LEVEL ID,                                     
          -- this apparently unnecessary cast does the trick
          CAST( TRUNC(SYSDATE) + LEVEL AS DATE) MyDate, 
          to_char(LEVEL) STRING
   FROM   dual
   CONNECT BY LEVEL < 5)
 SELECT CAST(COLLECT(MyDate) AS date_array)
 FROM   q

Да ... но почему ??

Действительно, кажется, что эти два значения не совсем одно и то же, даже если видимые значения на самом деле одинаковы:

 select sysdate, cast (sysdate as date) from dual

Итак, я выкопал внутреннее представление двух значений, применив к ним функцию «dump»:

 select dump(sysdate), dump(cast (sysdate as date)) from dual

и вот результаты, которые я получил:

DUMP(SYSDATE                    )  -> Typ=13 Len=8: 226,7,11,9,19,20,47,0   
DUMP(CAST(SYSDATEASDATE) as DUAL)  -> Typ=12 Len=7: 120,118,11,9,20,21,48

Внутренне они выглядят как два совершенно разных типа данных! один тип 12, а другой тип 13 ... и они имеют разную длину и представление.

В любом случае, я обнаружил кое-что еще .. кажется, кто-то еще заметил это: https://community.oracle.com/thread/4122627

На вопрос есть ответ, указывающий на этот документ: http://psoug.org/reference/datatypes.html

, в котором содержится длинное примечание о датах ... выдержка из него гласит:

"Что случилось? Указанная выше информация неверна или DUMP () функция не обрабатывает значения DATE? Нет, вы должны посмотреть на "Typ =" значения, чтобы понять, почему мы видим эти результаты. ". Тип данных возвращается 13, а не 12, внешний тип данных DATE. Это происходит потому что мы полагаемся на функцию TO_DATE! Внешний тип данных 13 является внутренняя c-структура, длина которой варьируется в зависимости от того, как c-компилятор представляет структуру. Обратите внимание, что значение Len = 8 а не 7. Тип 13 не является частью опубликованных интерфейсов 3GL для Oracle и используется для вычисления даты в основном в PL / SQL операции. Обратите внимание, что тот же результат можно увидеть при DUMPing значение SYSDATE. "

В любом случае, повторюсь: я думаю, что это ошибка, но, по крайней мере, я нашел обходной путь: используйте явное приведение к DATE.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...