を使用してOracleデータベースにいくつかのチェックを実装しようとしているXQuery
ときに、2つの日付が同じかどうかを比較する必要がありますが、 へのキャスト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()
上記のドキュメントを として渡すときにこの値を選択すると$doc
、期待される出力が得られます。
2015-09-11+00:00
Ok。時間部分が削除されたようですが、比較は失敗します:
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