2

を使用して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

アップデート

collapsarAlex 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
4

2 に答える 2

2

リテラルの日付値を dateTime 値に持ち上げると、うまくいきます (提供された dateTime 値から適切な時刻オフセットを抽出します)。

 xs:dateTime($doc/root/date_value) eq fn:dateTime(xs:date('2015-09-11'), xs:time(xs:dateTime($doc/root/date_value)))

このソリューションは、日付のみとして語彙化された入力に対しても機能します。

于 2015-10-26T17:30:50.637 に答える