考虑类型:
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数据类型的行为不同吗?
答案 0 :(得分:3)
这是我的发现...看来您遇到了一个错误,原因是计算的日期似乎具有与“数据库”日期不同的内部表示形式。我确实找到了解决方法,所以请继续阅读。
在我的oracle dev安装(Oracle 11g企业版11.2.0.4.0版-64位生产)上,我遇到了同样的问题。
但是...如果我创建一个包含您的测试数据的 physical 表:
create table test_data as
SELECT LEVEL ID,
TRUNC(SYSDATE) + LEVEL MyDate,
to_char(LEVEL) STRING
FROM dual
CONNECT BY LEVEL < 5
然后在此物理表上运行“ cast collect”运算符,它可以按预期工作:
-- 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
好像oracle认为计算的日期与物理日期
因此,我尝试使用明确的强制转换和EUREKA来“说服” oracle我提供的数据实际上是正常的DATE值!这可以正确地完成工作:
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。Type13不是已发布的3GL接口的一部分 Oracle,主要用于PL / SQL中的日期计算 操作。请注意,将 值SYSDATE。”
无论如何,我重复:我认为这是一个错误,但至少我找到了一种解决方法:对DATE使用显式强制转换。