[英]Oracle sql WITH clause and EXTRACT function
我试图了解下面两个查询之间的区别。 第二个引发语法错误。 有人可以帮忙吗?
1。
select
extract(year from (sysdate - to_date('2002-12-25')) year to month) Y
from dual;
2。
with age(d) as
(
select (sysdate - to_date('2002-12-25')) from dual
)
select
extract(year from (age.d) year to month) Y
from age;
错误:ORA-30083:在间隔值表达式30083中发现语法错误。00000-“在间隔值表达式中发现语法错误” *原因:在分析间隔值时发现语法错误
在第二个查询中,有NUMBER个值sysdate - to_date('2002-12-25')
。 您不能从数字中EXTRACT
年份。
在第一个查询中,您将数字转换回日期间隔数据类型之一。
-- datatype: internal NUMBER of a DATE subtraction
SELECT dump(sysdate - to_date('2002-12-25', 'YYYY-MM-DD'))
FROM dual;
-- datatype: INTERVAL YEAR TO MONTH
SELECT dump((sysdate - to_date('2002-12-25', 'YYYY-MM-DD')) year to month)
FROM dual;
-- datatype: NUMBER
SELECT dump(extract(year from (sysdate - to_date('2002-12-25', 'YYYY-MM-DD')) year to month))
FROM dual;
DUMP返回一个VARCHAR2值,其中包含数据类型代码,字节长度和expr的内部表示形式。
您的问题可以简化为以下原因:
select (sysdate - date '2002-12-25') year to month from dual;
(SYSDA
------
+14-03
但不会将sysdate - date '2002-12-25'
产生的相同数字插入相同的调用中,无论是否带有括号,都可以使用各种组合:
select (5217.4197) year to month from dual;
ORA-30083: syntax error was found in interval value expression
问题在于这两个数字实际上在内部是不同的。 如@hinoff所建议,您可以使用dump()
函数来检查它们:
select dump(sysdate - date '2002-12-25')
from dual;
DUMP(SYSDATE-DATE'2002-12-25')
-----------------------------------
Typ=14 Len=8: 97,20,0,0,195,143,0,0
select dump(5217.4197) from dual;
DUMP(5217.4197)
----------------------------
Typ=2 Len=5: 194,53,18,42,98
类型2 记录为number
。 并在MoS文档ID 1031902.6中进一步说明。
如果您将计算显式转换为2型数字,则会得到相同的错误:
select (cast(sysdate - date '2002-12-25' as number)) year to month from dual;
ORA-30083: syntax error was found in interval value expression
类型14似乎是一个未记录的内部表示形式,并且Oracle能够-在内部-以一种普通2型数字无法实现的方式在时间间隔之间来回转换。
您可以使用numtodsinterval(5217.4197, 'DAY')
将数字转换为间隔,但是由于日秒间隔和年月间隔不兼容,因此无法从中提取年数(是有道理的,因为一年中的天数会有所不同)。
如果尝试使用时间戳而不是日期来避免出现类似的问题,那么您会看到类似的问题:
select (systimestamp - timestamp '2002-12-25 00:00:00') year to month from dual;
(SYSTI
------
+14-03
select dump(systimestamp - timestamp '2002-12-25 00:00:00') from dual;
DUMP(SYSTIMESTAMP-TIMESTAMP'2002-12-2500:00:00')
------------------------------------------------------------------------
Typ=190 Len=24: 97,20,0,0,9,0,0,0,38,0,0,0,44,0,0,0,24,177,20,9,10,0,0,0
它也不是记录的间隔类型之一,但可以在内部转换为年月或日秒。 尝试在CTE中使用它也会失败; 使用extract(year from age.d)
会得到“ ORA-30076:提取源的无效提取字段”,因为此时它被视为一个DS间隔,而extract(year from (age.d) year to month)
返回到ORA-30083。
您最好从间隔切换到其他单位,例如月份:
with age(m) as
(
select months_between(sysdate, date '2002-12-25') from dual
)
select
trunc(age.m / 12) Y
from age;
Y
----------
14
如果还需要月份数,则可以使用trunc(remainder(age.m, 12))
。
或者,如果您确实需要间隔,请在CTE中进行转换:
with age(ym) as
(
select numtoyminterval(
months_between(sysdate, date '2002-12-25'), 'MONTH') from dual
)
select
extract(year from age.ym) Y
from age;
或更接近您的原件:
with age(ym) as
(
select (sysdate - date '2002-12-25') year to month from dual
)
select
extract(year from age.ym) Y
from age;
有趣的是, 文档显示这实际上是不允许的-“产生间隔值的六个组合在间隔表达式中有效”,而date-date并不是这六个组合之一 。 这可能表明类型14比数字类型更接近间隔。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.