在尝试使用 Oracle 数据库执行一些检查时,XQuery
我需要比较两个日期是否相同,但不能以明显的方式做到这一点,因为强制转换xs:date
并不会真正从xs:dateTime
.
查询本身似乎在另一个环境中运行良好(例如http://www.xpathtester.com/xquery)。
我是否错过了重要的事情,或者这种情况只是一个错误并且需要特殊的解决方法(转换为字符串值以进行比较,分别比较两个日期的年份、月份和日期等等)?
一个小例子...
假设我们有一个简单的 XML:
<root>
<date_value>2015-09-11T15:25:55</date_value>
</root>
并希望与忽略时间部分date_value
的固定值进行比较。xs:date('2015-09-11')
首先,将节点的内容转换为所需的类型,并通过将其转换为来删除时间部分xs:date
:
xs:date(xs:dateTime($doc/root/date_value))
XMLQuery()
如果我们在传递上面的文档时选择这个值as $doc
,我们会得到预期的输出:
2015-09-11+00:00
好的。似乎时间部分已删除,但比较失败:
xs:date(xs:dateTime($doc/root/date_value)) eq xs:date('2015-09-11')
返回false
,如果我们尝试查看表达式中的值之间的差异而不是比较它们:
xs:date(xs:dateTime($doc/root/date_value)) - xs:date('2015-09-11')
我们看到'PT15H25M55S'
,它们是完全匹配时间的一部分date_value
。
使用上述所有表达式进行查询以进行测试:
select
XMLCast(
XMLQuery( column_value
passing
xmltype(q'[
<root>
<date_value>2015-09-11T15:25:55</date_value>
</root>
]') as "doc"
returning content
)
as varchar2(4000)
) result_value,
column_value expression
from
table(sys.odcivarchar2list(
q'[ xs:date(xs:dateTime($doc/root/date_value)) ]',
q'[ xs:date('2015-09-11') ]',
q'[ xs:date(xs:dateTime($doc/root/date_value)) eq xs:date('2015-09-11') ]',
q'[ xs:date(xs:dateTime($doc/root/date_value)) - xs:date('2015-09-11') ]'
))
在此 Oracle 版本上重现的行为:
Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
PL/SQL Release 12.1.0.2.0 - Production
CORE 12.1.0.2.0 Production
TNS for IBM/AIX RISC System/6000: Version 12.1.0.2.0 - Production
NLSRTL Version 12.1.0.2.0 - Production
和
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production
PL/SQL Release 11.2.0.3.0 - Production
CORE 11.2.0.3.0 Production
TNS for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
NLSRTL Version 11.2.0.3.0 - Production
更新
感谢collapsar和Alex Poole的回答,它们给了我关于正确解决方法的主要想法。但是为了解释问题的核心,我过度简化了我们的用例,其中包括一些日期算术和现实世界的解决方法,看起来像下面的查询。
select
XMLCast(
XMLQuery(
q'[
let
$date1 := fn:dateTime(
adjust-date-to-timezone(
xs:date(xs:dateTime($doc/root/date_value)),
()
),
adjust-time-to-timezone( xs:time('00:00'), ())
),
$date2 := fn:dateTime(
adjust-date-to-timezone(
xs:date(xs:dateTime($doc/root/date_value2)),
()
),
adjust-time-to-timezone( xs:time('00:00'), ())
)
return
$date1 + xs:yearMonthDuration('P1Y') - xs:dayTimeDuration('P1D')
eq
$date2
]'
passing
xmltype(q'[
<root>
<date_value>2015-09-11T01:02:03-11:00</date_value>
<date_value2>2016-09-10T10:20:30+13:00</date_value2>
</root>
]') as "doc"
returning content
)
as varchar2(4000)
) result_value
from
dual