ヘッダーをスキップ
Oracle® XML DB開発者ガイド
11gリリース2 (11.2)
B70200-03
  目次へ移動
目次
索引へ移動
索引

前
 
次
 

5 Oracle XML DBでのXQueryの使用

この章では、Oracle XML DBでのXQuery言語の使用方法を説明します。XQuery言語でのOracle XML DBサポート、たとえばSQL/XML関数XMLQueryおよびXMLTable、それにSQL*Plus XQUERYコマンドについて説明します。

この章の内容は次のとおりです。

Oracle XML DBにおけるXQueryの概要

Oracle XML DBのXQuery言語サポートは、SQL/XML関数XMLQueryおよびXMLTableのネイティブ実装により提供されています。便宜性の観点から、SQL*PlusのコマンドXQUERYも用意されており、XQuery式を直接入力することができます。実質的に、このコマンドにより、SQL*PlusはXQueryコマンドライン・インタプリタになります。

Oracle XML DBは、SQL/XML関数XMLQueryXMLTableXMLExistsおよびXMLCastに引数として渡されるXQuery式をコンパイルします。このコンパイルにより、SQL問合せブロックと、SQL/XML関数とXPath関数を使用する演算子ツリーが作成されます。XMLQueryXMLTableXMLExistsまたはXMLCastを含むSQL文は一括してコンパイルおよび最適化され、リレーショナル・データベースとXQuery特有の最適化テクノロジの両方を活用します。使用するXML記憶域と索引付けメソッドにより、XPath関数をさらに最適化することができます。結果として生じる最適化された演算子ツリーは、ストリーム方式で実行されます。


関連項目:


XQuery言語の概要

Oracle XML DBはXQuery言語の最新バージョンの仕様、W3C XQuery 1.0勧告をサポートしています。このセクションでは、XQuery言語の簡単な概要を示します。詳細は、XQuery言語に関する最新の書籍や、http://www.w3c.orgから入手できる、XQueryを定義している標準に関する文書を参照してください。

シーケンスに基づく関数言語

XQuery 1.0はXMLデータの問合せのために設計されたW3C言語です。多くの点でSQLに類似していますが、SQLが単に構造化されたリレーショナル・データを問い合せるために設計されているのに対し、XQueryは、様々なデータ・ソースの半構造化されたXMLデータを問い合せるために特に設計されています。XQueryは、XMLデータがあれば、Webサービスからアクセスできるデータベース表に格納されているか、他の方法でその場で作成されるかに関係なく、XMLデータを問い合せるためにいつでも使用できます。XMLデータの問合せの他に、XQueryはXMLデータの構成にも使用できます。この点で、XQueryはXSLTやその他のSQL/XMLパブリッシング関数(XMLElementなど)の代用として使用できます。

XQueryは、XML Information Set (Infoset)データ・モデルとXML Schema型体系を統合した、Post-Schema-Validation Infoset (PSVI)データ・モデルに基づいています。XQueryではシーケンスに基づく新しいデータ・モデルが定義されています。XQuery式の結果がシーケンスです。XQueryは常にシーケンスの操作に関わります。このためXQueryは集合操作言語に類似しています。ただしシーケンスは順序付けされていて、重複項目を含むことができる点が異なります。XQueryシーケンスが他の言語のシーケンスと異なる点は、ネストされたXQueryシーケンスは実際の効果において常にフラット化されるという点です。

多くの場合、シーケンスを順序のないものとして処理することにより最適化を促進できます。ただしそれは可能な場合に限られ、ユーザーの責任となります。この順序なしモードは、ネストされた反復(for)の処理で順序を結合する場合や、XPath式を処理する場合に適用できます(たとえば/a/bでは、一致するb要素は文書順序に関係なく処理できます)。

XQueryシーケンスはゼロ個以上の項目から構成されています。項目は、アトム型(スカラー)の値またはXMLノードです。項目は、XML Schemaの型に基づくリッチ型体系を使用して型指定されます。この型体系は、ブール、数値、および文字列といった単純なスカラー型に制限されていたXPath 1.0から大きく変更された部分です。

XQueryは関数言語です。このため、評価され(XQueryではシーケンス)を戻す、可能なの集合からなります。XQueryは関数言語なので、通常は参照が透過的です。同じコンテキストで評価された同じ式同じ値を戻します。

こうした数学的長所の例外には、次のものがあります。

  • 外部環境との相互作用から値を導出するXQuery式。たとえば、fn:current-time(...)またはfn:doc(...)といった式は常に同じ値を戻すとはかぎりません。これは、それらの式が、変化する外部の条件に依存しているためです(時刻の変化、ターゲット文書のコンテンツの変化)。

    fn:docのような場合には、XQueryは単一の問合せの実行の内部で参照が透過的なものと定義されます。単一の問合せの内部では、同じ引数を伴うfn:docの呼出しは、同じ文書を結果とします。

  • 個別のXQuery言語の実装に依存するものとして定義されているXQuery式。そうした式の評価結果は、実装に応じて異なる場合があります。関数fn:docは、本質的に実装により定義される関数の例です。

参照の透過性は、XQuery変数にも適用されます。同じコンテキストでの同じ変数は同じ値を持ちます。関数言語はこの点で、数学で言う形式主義に似ており、手続き型、または命令型のプログラミング言語とは異なっています。手続き型言語の変数は、実際にはメモリー位置の名前で、現在の値や状態を持っており、任意の時点におけるその内容により表現されます。XQueryなど宣言型言語における変数は、実際には静的な値の名前です。

XQuery式

XQuery式では大/小文字が区別されます。式には次のものが含まれます。

  • 1次式: リテラル、変数、または関数アプリケーション。変数名は、たとえば$fooのように、ドル記号($)で始まります。リテラルには、数値、数値、文字、または実体参照。

  • XPath式: 任意のXPath式。XPath 2.0標準はXQueryのサブセットになります。

  • FLWOR式: 最も重要なXQuery式で、次の要素を順番に並べたもので構成されています。FLWORという名もそれに由来しています。forletwhereorder byreturn

  • XQueryシーケンス: カンマ(,)コンストラクタはシーケンスを作成します。unionintersectといったシーケンス操作関数も使用できます。XQueryシーケンスはすべて、事実上フラットです。ネストされたシーケンスは、フラット化された同等のものとして処理されます。このため、たとえば(1, 2, (3, 4, (5), 6), 7)(1, 2, 3, 4, 5, 6, 7)として処理されます。(42)などの単一シーケンスは、大部分のXQueryコンテキストで、単一項目42と同じ動作をします。前述のように、任意のXQuery式の結果はシーケンスです。

  • 直接(リテラル)構成: XML要素と属性の構文により、要素と属性が自動的に構成されます。構文に表記したとおりに使用されることになります。たとえば、XQuery式<a>33</a>により、XML要素<a>33</a>が構成されます。

  • 計算による(動的)構成: 計算された値を使用して、実行時にXMLデータを構成できます。たとえば、次のXQuery式によりこのXMLデータ<foo toto="5"><bar>tata titi</bar> why? </foo>が構成されます。

    <foo>attribute toto {2+3},
         element bar {"tata", "titi"},
         text {" why? "}</foo>
    

    この例では、要素fooが直接構成で、他の部分の構成は計算されたものです。実践では、計算されるコンストラクタの引数はリテラル(toto"tata"など)ではなく式(2+3など)で、評価されます。要素や属性コンストラクタの名前と値引数は、どちらも計算できます。中カッコ({, })は、XQuery式を評価対象外にするのに使用します。

  • 条件式: 通常どおりですが、式の各部分が任意の式になることに注意してください。たとえば、この条件式では、任意のXQuery式が各部分式(somethingsomethingElseexpression1、およびexpression2)に入ります。

     if (something < somethingElse) then expression1 else expression2
    
  • 数式、リレーショナル式 – 通常どおりですが、各リレーショナル式が(ブール脚注1)値を戻すことに注意してください。次に例を示します。

    2 + 3
    42 < $a + 5
    (1, 4) = (1, 2)
    5 > 3 eq true()
    
  • 量化式: 全称(every)および存在(some)関数を使用してFLWOR式を簡単に使用できる場合があります。次に例を示します。

    every $foo in doc("bar.xml")//Whatever satisfies $foo/@bar > 42
    some $toto in (42, 5), $titi in (123, 29, 5) satisfies $toto = $titi
    
  • 正規表現: XQueryの正規表現はXML Schema1.0およびPerlに基づいています。(「XQueryの関数と演算子のサポート」を参照)

  • 型表現: XQuery型を表現するXQuery式。たとえば、item()node()attribute()element()document-node()namespace()text()xs:integerxs:string脚注 2 

    型表現は、次のような出現インジケータを持てます。?(オプション。0回または1回)、*(0回以上)、+(1回以上)。たとえば、document-node(element())*item()+attribute()?

    XQueryには、型と組み合せて使用する演算子もあります。cast ascastable astreat asinstance の、typeswitch、およびvalidateなどです。たとえば、"42" cast as xs:integerは、値が整数の2である式です。(厳密には、値が型を表現していないので、これは型表現ではありません)。

FLWOR式

XQuery一般について考えた場合、FLWOR式には多くの学習事項があります。この項の説明は簡単な概要にすぎません。

FLWORはXQueryで最も一般的な式構文です。FLWOR(「フラワー」と読みます)は、forletwhereorder by、およびreturnを表しています。FLWOR式には1つ以上のforまたはlet句と、1つのreturn句を持ちます。1つのwhereおよびorder by句がオプションです。

  • for: 1つ以上の変数を任意の値に順にバインドします。つまり、各変数に対し反復を行いますが、変数を各回の反復で別の値にバインドします。

    各回の反復で、変数は出現する順にバインドされ、forリストで$laterの前にリストされた変数$earlierの値が、変数$laterのバインドで使用されます。たとえば、次の式は、2回目の反復で$i4にバインドし、$j6(2+4)にバインドします。

     for $i in (3, 4), $j in ($i, 2+$i)
    
  • let: 1つ以上の変数をバインドします。

    forと同様、letでも、letのバインディング・リストで先にリストされている別の変数を使用して(またはforletで囲むことにより)、変数を計算した値にバインドできます。たとえば、次の式は$j5(3+2)にバインドします。

    let $i := 3, $j := $i + 2
    
  • where: forおよびletの変数バインディングを特定の条件に応じてフィルタします。SQLのWHERE句に類似しています。

  • order by: whereフィルタリングの結果をソートします。

  • return: 順序付けとフィルタリングがされた値を構成します。これがFLWOR式の最終的な結果です。フラット化されたシーケンスになります。

forletは、SQLのFROM句に対して同じように機能します。式whereは、SQLのWHERE句と同じように機能し、式order byはSQLのORDER BYと似ています。式returnは、SQLのSELECTに似ています。両方の言語で名前が共通している2つのキーワード(whereorder by)を除いて、FLWOR句の順序はSQL句の順序と反対ですが、対応する句の意味は非常に類似しています。

FLWOR式(order byを含む)の使用は、文書の順序と異なる順序でXQueryシーケンスを構成する唯一の方法です。

SQL/XML関数XMLQUERYおよびXMLTABLE

SQL/XML関数XMLQueryXMLTableXMLExistsXMLCastは、SQL/XML標準により、SQL言語とXQuery言語の一般インタフェースとして定義されています。他のSQL/XML関数と同様、これらの関数を使用すると、SQLとXML、両方の強力な機能と柔軟性を活用できます。これらの関数を使用すると、リレーショナル・データを使用したXMLデータの構成、XML同様のリレーショナル・データに対する問合せ、およびXMLデータからのリレーショナル・データの構成が可能です。

SQL関数XMLExistsおよびXMLCastについては、このマニュアルの別の項で説明します。この項では、関数XMLQueryXMLTableについて説明しますが、本章の例の大半はXMLExistsおよびXMLCastも使用します。一般的な使用方法は次のとおりです。

  • XMLQueryXMLCastは通常、SELECTリストで使用します。

  • XMLTableは一般的にSQLのFROM句で使用します。

  • XMLExistsは通常、SQLのWHERE句で使用します。

XMLQueryXMLTableの両方がXQuery式を評価します。XQuery言語では、式は常に項目のシーケンスを戻します。関数XMLQueryはこのシーケンスの項目を集計し、単一のXML文書または断片を戻します。関数XMLTableは、XQueryシーケンスからの1つの項目を各行に含むSQL表を戻します。


関連項目:


Oracle XML DBのXMLQUERY SQL/XML関数

SQL/XML関数XMLQueryを使用して、XMLデータの構成や問合せができます。この関数は引数としてXQuery式、文字列としてリテラル、そしてオプションで、XQueryコンテキスト項目をSQL式として取ります。コンテキスト項目は、XQuery式を評価する際のXPathコンテキストを確立します。この他に、XMLQueryは、XQuery式の評価の際にXQuery変数にバインドされた値を持つ任意の数のSQL式を引数として受け取ります。関数はXQuery式の評価結果をXMLTypeインスタンスとして戻します。

図5-1 XMLQUERYの構文

図5-1の説明が続きます
「図5-1 XMLQUERYの構文」の説明

XML_passing_clause::= 

xml_passing_clause.gifの説明が続きます
図xml_passing_clause.gifの説明

  • XQuery_stringは完結したXQuery式で、プロローグをリテラル文字列として含む場合があります。

  • XML_passing_clauseはキーワードPASSINGに1つ以上のSQL式(expr)を続けたもので、それぞれXMLTypeインスタンスまたはSQLスカラー・データ型の(つまり、オブジェクト・データ型でもコレクション・データ型でもない)インスタンスを戻します。それぞれの式(expr)は、適切にキャストされた表またはビューの列の値、PL/SQL変数、バインド変数のいずれかになります。1つを除いてすべての式では、その後にASおよびXQuery identifierが続いている必要があります。それぞれのexprの評価結果は、対応するidentifierにバインドされ、続いてXQuery_stringが評価されます。AS句に続いていないexprがあった場合、そのexprの評価結果は、XQuery_stringを評価する際のコンテキスト項目として使用されます。Oracle XML DBではBY VALUEを渡すことはできますが、BY REFERENCEは渡せないため、BY VALUE句は暗黙的で、省略可能です。

  • RETURNING CONTENTは、XMLQueryのアプリケーションが戻す値が、パラメータ化されたXML型XML(CONTENT)のインスタンスであり、パラメータ化された型XML(SEQUENCE)のインスタンスではないことを示します。これは拡張Infosetデータ・モデルに準拠した文書フラグメントです。このため、任意の数の子を持つ単一の文書ノードとなります。子はそれぞれ任意のXMLノード型を取ることができ、特に、テキスト・ノードになることが可能です。

    SQL/XML関数XMLQueryでOracle XML DBがサポートするのはRETURNING CONTENT句のみです。RETURNING SEQUENCE句はサポートしていません

XMLTypeの列、表、またはビューは、関数XMLQueryのコンテキスト項目引数として渡すことができます。例として、例5-8を参照してください。

リレーショナル表やビューに対して、XMLデータのときのように最初にSQL/XMLビューを作成する必要なく問合せを実行するには、XQuery関数fn:collectionをXQuery式内で使用し、URIスキーム名oradbを使用するURIを、データのデータベースの場所とともに引数として引き渡します。「URIスキームoradb: XQueryを使用した表またはビュー・データの問合せ」を参照してください。


注意:

Oracle Database 11gリリース2より前のリリースでは、一部のユーザーは一部の処理の実行にOracle SQL関数extractおよびextractValueを使用していました。これらの処理は、SQL/XML関数XMLQueryおよびXMLCastを使用するとより効率的に実行できます。SQL関数extractおよびextractValueは、Oracle Database 11gリリース2で非推奨になりました。


関連項目:

  • SQL/XML関数XMLQueryの定義の詳細は、http://www.sqlx.orgを参照してください。

  • Oracle DatabaseにおけるSQL/XML関数XMLQueryの参考情報は、『Oracle Database SQL言語リファレンス』を参照してください。


Oracle XML DBのXMLTABLE SQL/XML関数

SQL/XML関数XMLTableは、XQuery式の評価結果を新規の仮想表に対するリレーショナル行と列に分解します。その仮想表は、既存のデータベース表に挿入したり、SQLを使用して(join式など)問い合せたりできます(例5-9を参照)。SQLのFROM句でXMLTableを使用します。

図5-2 XMLTABLEの構文

図5-2の説明が続きます
「図5-2 XMLTABLEの構文」の説明

XML_namespaces_clause::= 

xml_namespaces_clause.gifの説明が続きます
図xml_namespaces_clause.gifの説明

XMLTABLE_options::= 

xmltable_options.gifの説明が続きます
図xmltable_options.gifの説明

XML_passing_clause::= 

xml_passing_clause.gifの説明が続きます
図xml_passing_clause.gifの説明

XML_table_column::= 

xml_table_column.gifの説明が続きます
図xml_table_column.gifの説明

  • XQuery_stringは完結したXQuery式で、プロローグをリテラル文字列として含む場合があります。式の値は XMLTable関数への入力となります。つまり、このXQueryの結果が分解されリレーショナル・データとして格納されます。

  • オプションのXMLNAMESPACES句にはXML名前空間宣言が含まれており、XML_table_columnPATH句で、XQuery_stringおよびXPath式により参照されます。

  • XML_passing_clauseはキーワードPASSINGに1つ以上のSQL式(expr)を続けたもので、それぞれXMLTypeインスタンスまたはSQLスカラー・データ型の(つまり、オブジェクト・データ型でもコレクション・データ型でもない)インスタンスを戻します。それぞれの式(expr)は、適切にキャストされた表またはビューの列の値、PL/SQL変数、バインド変数のいずれかになります。1つを除いてすべての式では、その後にASおよびXQuery identifierが続いている必要があります。それぞれのexprの評価結果は、対応するidentifierにバインドされ、続いてXQuery_stringが評価されます。AS句に続いていないexprがあった場合、そのexprの評価結果は、XQuery_stringを評価する際のコンテキスト項目として使用されます。Oracle XML DBではBY VALUEを渡すことはできますが、BY REFERENCEは渡せないため、BY VALUE句は暗黙的で、省略可能です。

  • オプションのCOLUMNS句は、XMLTableにより作成される仮想表の列を定義します。

    • COLUMNS句を省略した場合、XMLTableは、COLUMN_VALUEという名前で単独のXMLType疑似列を戻します。

    • FOR ORDINALITYは、columnが生成される行数の列になることを示します(SQLデータ型NUMBER)。最大で1個のFOR ORDINALITY句がある必要があります。

    • FOR ORDINALITY列を除き、生成された各列に列のデータ型を指定する必要があります。XMLTypeまたは任意のSQLデータ型(構文の説明でdatatypeと呼ばれる)を指定できます。

    • オプションのPATH句は、XQuery式stringにより扱われたXQueryの結果の一部がcolumnコンテンツの一部として使用されることを示しています。複数のPATH句を使用してXQueryの結果を異なる仮想表の列に分割できます。

      PATHを省略した場合は、XQuery式がcolumnであるものと仮定されます。たとえば、次の2つの式は等価です。

      XMLTable(... COLUMNS foo)
      XMLTable(... COLUMNS foo PATH 'FOO')
      

      XQuery式stringXQuery_stringに対して相対的であるため、相対パスの表記にする必要があります。

    • オプションのDEFAULT句は、PATH式の結果が空のシーケンス(またはNULL)になる場合に使用する値を指定します。そのexprは、評価されてデフォルト値を生成するXQuery式です。


関連項目:

  • SQL/XML関数XMLTableの定義の詳細は、http://www.sqlx.orgを参照してください。

  • Oracle DatabaseにおけるSQL/XML関数XMLTableの参考情報は、『Oracle Database SQL言語リファレンス』を参照してください。



注意:

Oracle Database 11gリリース2より前のリリースでは、一部のユーザーは一部の処理の実行に、SQL TABLEコレクション式でOracle SQL関数XMLSequence(TABLE(XMLSequence(...)))を使用していました。これらの処理は、SQL/XML関数XMLTableを使用するとより効率的に実行できます。関数XMLSequenceは、Oracle Database 11gリリース2で非推奨になりました。

SQL TABLEコレクション式の詳細は、『Oracle Database SQL言語リファレンス』を参照してください。


XQueryの用途

SQL/XML生成関数またはXSLTを使用して実行される処理には、XQueryを使用して実行できるものが多く、両者の用途は多くの点で一致しています。あるタスクを実行する際にどのツールを使用するかは、様々な考慮事項に基づいて決定されるものであり、その考慮事項の多くはOracle Database以外に関連するものです。このような一般的な問題については、外部のドキュメントを参照してください。

一般的には、XMLデータに主眼を置いている場合はXQueryが使用され、リレーショナル・データに主眼を置いている場合はSQL/XML生成関数(XMLElementXMLAggなど)が使用されます。

他の条件が同じであれば、既存のXML文書から抽出されたフラグメントに基づいて問合せによってXML文書を構成する場合は通常、リレーショナル・データからスカラー値を抽出し、SQL/XML生成関数を使用して目的のXMLデータを構成するよりも、通常はXQueryのFLOWR式が単純になります(そのためコードのメンテナンスも簡単になります)。一方、既存のリレーショナル・データに基づいて問合せによってXML文書を構成する場合は、通常、SQL/XML生成関数を使用する方が適しています。

Oracle XML DBに関しては、SQL/XML生成関数を使用しても、XMLQueryおよびXMLTableを使用しても、期待できるパフォーマンスは、同じ一般的なレベルです。これは、いずれも最適化のリライト対象になります。

事前定義のネームスペースと接頭辞

次の名前空間と接頭辞は、Oracle XML DBでXQueryとともに使用するように事前定義されています。

表5-1 事前定義の名前空間と接頭辞

接頭辞 名前空間 説明

ora

http://xmlns.oracle.com/xdb

Oracle XML DB名前空間

local

http://www.w3.org/2003/11/xpath-local-functions

XPathのローカル関数宣言名前空間

fn

http://www.w3.org/2003/11/xpath-functions

XPath関数名前空間

xml

http://www.w3.org/XML/1998/namespace

XML名前空間

xs

http://www.w3.org/2001/XMLSchema

XML Schema名前空間

xsi

http://www.w3.org/2001/XMLSchema-instance

XML Schemaインスタンス名前空間


これらの接頭辞は、あらかじめXQuery式プロローグで宣言しなくてもXQuery式で使用できます。また、xml以外は、すべてプロローグ内で再定義できます。ora以外の接頭辞はすべて、XQuery標準で事前定義されています。

URIスキームoradb: XQueryを使用した表またはビュー・データの問合せ

XQuery関数fn:docfn:collectionを使用して、Oracle XML DBリポジトリのリソースに対して問い合せることができます — 「XQueryを使用したOracle XML DBリポジトリ内でのXMLデータの問合せ」を参照してください。この項では、XQuery関数fn:collectionを使用した、データベースの表およびビュー内のデータの問合せについて説明します。

これを行うには、問い合せる表またはビューを指定する、関数fn:collectionのURI引数を渡します。Oracle URIスキーマoradbによりこの使用が識別されます。これがないと、引数はリポジトリの場所として扱われます。

問い合せる表またはビューは、リレーショナルまたはXMLType型のどちらでもかまいません。リレーショナルの場合は、データはその場で変換され、XMLとして扱われます。fn:collectionによって戻される結果は、常にXQueryシーケンスです。

  • XMLTypeの表については、fn:collectionによって戻される各XML文書のルート要素は、表のXML文書のルート要素と同じです。

  • リレーショナルの表の場合、fn:collectionによって戻される各XML文書のルート要素はROWです。ROW要素の子は、表の列と同じ名前(大文字)を持つ要素です。子要素の内容は、列のデータに一致します。列の型がXMLTypeの場合は内容はXML要素で、それ以外の場合(列はスカラー型)は内容はxs:string型です。

fn:collectionに引き渡されるURI要素の形式は、次のとおりです。

  • データベース・スキーマDB-SCHEMA内のXMLTypeまたはリレーショナルの表あるいはビューTABLEの場合

    oradb:/DB-SCHEMA/TABLE/
    

    TABLEがバブリック・シノニムか、TABLEが現在ログイン中のデータベース・ユーザーがアクセス可能な表またはビューの場合、DB-SCHEMAPUBLICを使用できます。

  • リレーショナルの表またはビュー内のXMLType列の場合

    oradb:/DB-SCHEMA/REL-TABLE/ROWPRED/X-COL
    

    REL-TABLEはリレーショナル表またはビューで、PREDXMLType列と関係しないXPath述語です。X-COLREL-TABLEXMLType列です。PREDはオプションで、DB-SCHEMAREL-TABLEおよびX-COLは必須です。

オプションのXPath述語PREDは、次の条件を満たす必要があります。

  • XMLType列が一切関係しない。

  • 一般的な同等の結合(and)と分離(or)および不等の比較(=!=><>=<=)のみが関係している。

  • それぞれの比較演算について、REL-TABLEの両側の名前(XML以外)列、またはある列と他方のような一方の名前が、表5-2で指定された正しい型の値である。他の型を使用すると、エラーが発生します。

表5-2 oradb式: 比較用の列の型

リレーショナルの列の型 XQuery値の型

VARCHAR2CHAR

xs:stringまたは文字列リテラル

NUMBERFLOATBINARY_FLOATBINARY_DOUBLE

xs:decimalxs:floatxs:double、または数値リテラル

DATETIMESTAMPTIMESTAMP WITH TIMEZONETIMESTAMP WITH LOCAL TIMEZONE

xs:datexs:timexs:dateTime

INTERVALYEARTOMONTH

xs:yearMonthDuration

INTERVALDAYTOSECOND

xs:dayTimeDuration

RAW

xs:hexBinary

ROWID

xs:stringまたは文字列リテラル


たとえば、このXQuery式は、表oe.warehousesXMLTypewarehouse_specにあって、列warehouse_idの値が6より小さい行のすべてのXML文書を表します。

fn:collection('oradb:/OE/WAREHOUSES/ROW[WAREHOUSE_ID < 6]/WAREHOUSE_SPEC')

Oracle XQuery拡張関数

Oracle XML DBには、W3C標準に用意されているものの他に、いくつかのXQuery関数が追加されています。それらの追加関数はOracle XML DB名前空間、http://xmlns.oracle.com/xdbにあります。この名前空間は事前定義の接頭辞oraを使用します。この項ではこれらのOracle拡張関数を説明します。

ora:contains XQuery関数

ora:contains構文

ora:contains (input_text, text_query [, policy_name] [, policy_owner])

XQueryおよびXPath関数ora:containsは、SQL/XML関数XMLQueryXMLTableまたはXMLExistsへのコールのXQuery式内で使用できます。これは、全文述語を伴う構成検索を制限する場合に使用されます。関数ora:containsinput_texttext_queryと一致した場合は正の整数を戻し(数字が大きいほど、一致の関連性は高くなります)、一致しない場合はゼロを戻します。XQuery式内部で使用される場合(XPath式のみでなく)、XQueryの戻り型はxs:integer()です。XQuery式外部のXPath式で使用される場合、XPathの戻り型はnumberです。

引数input_textは単一のテキスト・ノードまたは属性に対して評価される必要があります。ora:containsにおけるtext_queryの構文と意味論は、いくつかの制限を伴う他はcontainsにおけるtext_queryと同一です。

ora:matches XQuery関数

ora:matches構文

ora:matches (target_string, match_pattern [, match_parameter])

XQuery関数ora:matchesを使用すると、正規表現を使用して文字列内のテキストを検索できます。target_string引数が正規表現match_pattern引数に一致していればtrue()を、それ以外の場合はfalse()を戻します。target_stringが空のシーケンスの場合はfalse()を戻します。オプションの引数match_parameterは、検索文字列を修飾するコードで、大文字/小文字の区別などを指定できます。

XQuery関数ora:matchesの動作はSQL条件REGEXP_LIKEと同じですが、引数の型はSQLデータ型ではなくXQuery型です。引数の型は次のとおりです。

  • target_stringxs:string?脚注3

  • match_pattern - xs:string

  • match_parameter - xs:string


関連項目:

SQL条件REGEXP_LIKEの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ora:replace XQuery関数

ora:replace構文

ora:replace (target_string, match_pattern, replace_string [, match_parameter])

XQuery関数ora:replaceを使用すると、正規表現を使用して文字列内のテキストを置換することができます。target_string内にある正規表現match_patternが出現するたびにreplace_stringに置換されます。置換の結果得られる新しい文字列を戻します。target_stringが空のシーケンスの場合は、空の文字列("")を戻します。オプションの引数match_parameterは、検索文字列を修飾するコードで、大文字/小文字の区別などを指定できます。

XQuery関数ora:replaceの動作はSQL関数regexp_replaceと同じですが、引数の型はSQLデータ型ではなくXQuery型です。引数の型は次のとおりです。

  • target_stringxs:string?脚注4

  • match_pattern - xs:string

  • replace_string - xs:string

  • match_parameter - xs:string

さらにora:replaceは引数replace_stringを必要とし(regexp_replaceではオプション)、位置や出現回数を表す引数は使用しません。検索は最初の文字から開始され、すべての出現箇所が置換されます。


関連項目:

SQL関数regexp_replaceの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。

ora:sqrt XQuery関数

ora:sqrt構文

ora:sqrt (number)

XQuery関数ora:sqrtは、数値引数の平方根を戻します。引数はXQuery型xs:decimalxs:float、またはxs:doubleのいずれかです。戻り値のXQuery型は引数と同じです。

ora:tokenize XQuery関数

ora:tokenize構文

ora:tokenize (target_string, match_pattern [, match_parameter])

XQuery関数ora:tokenizeでは、正規表現を使用して入力文字列target_stringを文字列のシーケンスに分割できます。正規表現match_patternと一致する部分文字列はそれぞれ、分割位置を示すセパレータとして扱われます。

トークンのシーケンスは、型xs:string*のXQuery値(xs:string値のシーケンス)として戻されます。target_stringが空のシーケンスの場合は、それが戻されます。オプションの引数match_parameterは、検索文字列を修飾するコードで、大文字/小文字の区別などを指定できます。

引数の型は次のとおりです。

  • target_stringxs:string?脚注5

  • match_pattern - xs:string

  • match_parameter - xs:string

Oracle XQuery拡張式プラグマ

W3CのXQuery仕様では、実装により定義された拡張式を実装で提供できます。XQuery拡張式は、カッコ({、 })で囲まれたXQuery式で、実装で定義されたプラグマが接頭辞になります。

Oracle実装では、この項で説明するプラグマが提供されます。ここに記載したプラグマ以外のプラグマは認識されません。その他のプラグマ、すなわち不正なプラグマ・コンテンツを持つプラグマ(例: (#ora:view_on_null something_else #))を使用すると、エラーが発生します。

ora:view_on_nullの例では、null_test表にVARCHAR2(10)型の列abがあり、列b(aではない)が空であるとします。

  • (#ora:defaultTable #) – リポジトリ・データの格納に使用されるデフォルトの表を指定します。これを使用して、Query関数fn:docまたはfn:collectionを使用するリポジトリ問合せのパフォーマンスを向上させます。「Oracle XQueryプラグマora:defaultTableの使用」を参照してください。

  • (#ora:invalid_path empty #) – 無効なXPath式のターゲットとなるノードがある場合、それが存在しないかのように処理します。次に例を示します。

    SELECT XMLQuery('(#ora:invalid_path empty #)
                     {exists($p/PurchaseOrder//NotInTheSchema)}'
                    PASSING OBJECT_VALUE AS "p" RETURNING CONTENT)
      FROM oe.purchaseorder p;
    

    oe.purchaseorderのXML Schemaでは、NotInTheSchemaのようなノードは、PurchaseOrderノードの子孫とし使用できません。プラグマがない場合、このような無効なXPath式を使用するとエラーが発生します。しかし、プラグマを使用すると、コール元のコンテキストは、XPath式にターゲット・ノードがないかのように動作します。この例では、コール元のコンテキストはXQuery関数existsで、空のノード・シーケンスが渡されると、XQueryのブール値falseを戻します。(この例ではXQuery関数existsは動作を説明するためのみに使用されています。プラグマは関数existsに特に関連付けられていません)。

  • (#ora:view_on_null empty #) – XQuery関数fn:collectionは、それぞれのNULL列に対して空のXML要素を戻します。たとえば、次の問合せでは、<ROW><A>x</A><B></B></ROW>が戻されます。

    SELECT XMLQuery('(#ora:view_on_null empty #)
                     {for $i in fn:collection("oradb:/PUBLIC/NULL_TEST")/ROW 
                      return $i}'
                    RETURNING CONTENT)
      FROM DUAL;
    
  • (#ora:view_on_null null #) – XQuery関数fn:collectionは、NULL列には要素を戻しません。たとえば、次の問合せでは、<ROW><A>x</A></ROW>が戻されます。

    SELECT XMLQuery('(#ora:view_on_null null #)
                     {for $i in fn:collection("oradb:/PUBLIC/NULL_TEST")/ROW 
                      return $i}'
                    RETURNING CONTENT)
      FROM DUAL;
    
  • (#ora:xq_proc #) – プラグマに続くXQuery式内のXQueryプロシージャのコールを最適化しないでください。かわりに機能上の評価を使用します。

    これは、SQLヒント/*+ NO_XML_QUERY_REWRITE */と同じ効果がありますが、プラグマの範囲は後に続くXQuery式のみです(SQL文全体ではありません)。


    関連項目:

    オプティマイザ・ヒントNO_XML_QUERY_REWRITEの詳細は、「XMLIndexの使用の無効化」を参照してください。

  • (#ora:xq_qry #) – プラグマに続くXQuery式を最適化してみてください。つまり、もし可能な場合は、機能面で評価しないでください。

    ora:xq_procora:xq_qryの両方の使用例として、次の問合せでは、XMLQueryに対するXQuery式の引数は、一般的に機能面で評価されますが、プラグマora:xq_qryの後に続くfn:collection部分式は可能なかぎり最適化されます。

    SELECT XMLQuery('(#ora:xq_proc#)   (: Do not optimize the XQuery expression :)
                     {for $i in (#ora:xq_qry#)   (: Optimize this subexpression :)
                                {fn:collection("oradb:/HR/REGIONS")},
                          $j in (#ora:xq_qry#)   (: Optimize this subexpression :)
                                {fn:collection("oradb:/HR/COUNTRIES")}
                      where $i/ROW/REGION_ID = $j/ROW/REGION_ID
                        and $i/ROW/REGION_NAME = $regionname
                      return $j}'
             PASSING CAST('&REGION' AS VARCHAR2(40)) AS "regionname"
               RETURNING CONTENT)
      AS asian_countries FROM DUAL;
    

XMLQUERYおよびXMLTABLEの例

XQueryは非常に汎用性と表現力に富む言語で、SQL/XML関数XMLQueryXMLTableおよびXMLExistsにより、それらの表現力と計算力がSQLの同様の長所と組み合されます。この項では、これら2つのSQL/XML関数でできることについて説明します。XMLExistsの詳細は、「XMLEXISTS SQL/XML関数」を参照してください。

Oracle XML DBでは、通常は次のようにXQueryを使用します。ここでの例は、それらの使用方法の違いを示すように構成されています。

例5-1は、この章の他の例の一部で使用するOracle XML DBリポジトリ・リソースを作成します。

例5-1 例で使用するリソースの作成

DECLARE
  res BOOLEAN;
  empsxmlstring VARCHAR2(300):= 
    '<?xml version="1.0"?>
     <emps>
       <emp empno="1" deptno="10" ename="John" salary="21000"/>
       <emp empno="2" deptno="10" ename="Jack" salary="310000"/>
       <emp empno="3" deptno="20" ename="Jill" salary="100001"/>
     </emps>';
  empsxmlnsstring VARCHAR2(300):=
    '<?xml version="1.0"?>
     <emps xmlns="http://example.com">
       <emp empno="1" deptno="10" ename="John" salary="21000"/>
       <emp empno="2" deptno="10" ename="Jack" salary="310000"/>
       <emp empno="3" deptno="20" ename="Jill" salary="100001"/>
     </emps>';
  deptsxmlstring VARCHAR2(300):=
    '<?xml version="1.0"?>
     <depts>
       <dept deptno="10" dname="Administration"/>
       <dept deptno="20" dname="Marketing"/>
       <dept deptno="30" dname="Purchasing"/>
     </depts>';
BEGIN
  res := DBMS_XDB.createResource('/public/emps.xml',   empsxmlstring);
  res := DBMS_XDB.createResource('/public/empsns.xml', empsxmlnsstring);
  res := DBMS_XDB.createResource('/public/depts.xml',  deptsxmlstring);
END;
/

XQueryとシーケンス

重要なことは、XQueryが汎用のシーケンス操作言語であるということです。式や結果は、XMLデータでなくてもかまいません。XQueryシーケンスは数値、文字列、ブール値、日付など任意のXQuery型の項目と、様々な型のXMLノード(document-node()element()attribute()text()namespace()など)を含むことができます。例5-2に例を示します。

例5-2 様々な型の項目シーケンスに適用されるXMLQuery

SELECT XMLQuery('(1, 2 + 3, "a", 100 to 102, <A>33</A>)'
                RETURNING CONTENT) AS output
  FROM DUAL;

OUTPUT
--------------------------
1 5 a 100 101 102<A>33</A>
 
1 row selected.

例5-2では、SQL/XML関数XMLQueryを、異なる様々な種類の項目を含むXQueryシーケンスに適用します。

  • 整数リテラル: 1

  • 算術式: 2 + 3

  • 文字列リテラル: "a"

  • 整数のシーケンス: 100 to 102

  • 構成されたXML要素ノード: <A>33</A>

例5-2は、カンマ演算子(,)とカッコ(())を使用してグループ化したシーケンスの構成も示しています。

シーケンス式100 to 102の評価結果はシーケンス(100, 101, 102)なので、XMLQueryの引数は、ネストされたシーケンスを含むシーケンスです。シーケンス引数は、XQueryシーケンスと同様、自動的にフラット化されます。実際の引数は、(1, 5, "a", 100, 101, 102, <A>33</A>)となります。

XQueryを使用したOracle XML DBリポジトリ内でのXMLデータの問合せ

この項では、XQueryとXMLデータをOracle XML DBリポジトリとともに使用する例を紹介します。XQuery関数fn:docfn:collectionは、それぞれリポジトリ内のファイルおよびフォルダのリソースを問い合せるときに使用します。この項の例では、XQuery関数fn:docを使用してXMLデータを含むリポジトリ・ファイルを取得し、FLWOR式の句forおよびletを使用してXQuery変数をそのデータの部分にバインドしています。

例5-3は、Oracle XML DBリポジトリ内の2つのXML文書リソース、/public/emps.xmlおよび/public/depts.xmlを問い合せます。fn:docの使用法および可能なFLWOR式のそれぞれの句を説明しています。

例5-3 for、let、order by、where、およびreturnを使用するFLOWR式

SELECT XMLQuery('for $e in doc("/public/emps.xml")/emps/emp
                 let $d :=
                   doc("/public/depts.xml")//dept[@deptno = $e/@deptno]/@dname
                 where $e/@salary > 100000
                 order by $e/@empno
                 return <emp ename="{$e/@ename}" dept="{$d}"/>'
                RETURNING CONTENT) FROM DUAL;

XMLQUERY('FOR$EINDOC("/PUBLIC/EMPS.XML")/EMPS/EMPLET$D:=DOC("/PUBLIC/DEPTS.XML")
--------------------------------------------------------------------------------
<emp ename="Jack" dept="Administration"></emp><emp ename="Jill" dept="Marketing"
></emp>
 
1 row selected.

例5-3では、各種のFLWOR句が次の操作を行っています。

  • for/public/emps.xml内のemp要素について反復を実行し、変数$eを各要素の値に順にバインドします。つまり、従業員全体のリストについて反復を実行し、$eを各従業員にバインドします。

  • letは変数$dを、/public/emps.xml内の、deptno属性が要素$edeptno属性と同じであるdept要素が持つdname属性のすべての値で構成されているシーケンスにバインドします(結合操作)。つまり、これは$dを、従業員$eの部門と同じ部門番号を持つすべての部門の名前にバインドします。(depts.xml内の各deptno値に対してdname値が一意であることもあり得ます)。forと異なりletは値に対して反復を行わないことに注意してください。この例で、$dは1度のみバインドされています。

  • forletを同時に使用すると、タプル($e, $d)のストリームを生成できます。ここで$eはある従業員、$dはその従業員が所属するすべての部門の名前(この場合は従業員の一意の部門の一意の名前)を表します。

  • whereはそのタプル・ストリームをフィルタリングし、給与が100,000を超える従業員のみを残します。

  • order byは、フィルタリングされたタプル・ストリームを従業員番号empnoでソートします(デフォルトでは昇順)。

  • returnは、各タプルについて1つのemp要素を構成します。それらの要素の属性enameおよびdeptが、それぞれ入力の属性enameおよび$dを使用して構成されます。出力内の要素名と属性名empおよびenameと入力文書emps.xml内の同じ名前の間に必然的な関係はないことに注意してください。

例5-4でもFLWOR式の句をそれぞれ使用しています。この例は、組込みXQuery関数 http://www.w3.org/2003/11/xpath-functionsの名前空間にあるXQuery関数doccountavg、およびintegerの使用方法を示しています。この名前空間は接頭辞fnにバインドされます。

例5-4 組込み関数を使用したFLOWR式

SELECT XMLQuery('for $d in fn:doc("/public/depts.xml")/depts/dept/@deptno
                 let $e := fn:doc("/public/emps.xml")/emps/emp[@deptno = $d]
                 where fn:count($e) > 1
                 order by fn:avg($e/@salary) descending
                 return
                   <big-dept>{$d,
                              <headcount>{fn:count($e)}</headcount>,
                              <avgsal>{xs:integer(fn:avg($e/@salary))}</avgsal>}
                   </big-dept>'
                RETURNING CONTENT) FROM DUAL;

XMLQUERY('FOR$DINFN:DOC("/PUBLIC/DEPTS.XML")/DEPTS/DEPT/@DEPTNOLET$E:=FN:DOC("/P
--------------------------------------------------------------------------------
<big-dept deptno="10"><headcount>2</headcount><avgsal>165500</avgsal></big-dept>
 
1 row selected.

例5-4では、各種のFLWOR句が次の操作を行っています。

  • forは、入力文書/public/depts.xml内のdeptno属性について反復を実行し、変数$dを各属性の値に順にバインドします。

  • letは変数$eを、入力文書/public/emps.xmlの、deptno属性が$dという値を持つすべてのemp要素で構成されるシーケンスにバインドします(join操作)。

  • Together, forletを同時に使用すると、タプル($d, $e)のストリームを生成できます。ここで$dは部門番号、$eはその部門の従業員の集合を表します。

  • whereはそのタプル・ストリームをフィルタリングし、1人以上の従業員を持つタプルのみを残します。

  • order byは、フィルタリングされたタプル・ストリームを平均給与の降順でソートします。平均は、名前空間fnのXQuery関数avgを、属性salaryの値に適用して計算します。この値は$eemp要素に連結されています。

  • returnは、order byで生成された各タプルについて1つのbig-dept要素を構成します。big-depttext()ノードには、$dにバインドされた部門番号が含まれます。XQuery関数countで指定されたとおり、headcount子要素には、従業員数が$eにバインドされて含まれます。avgsal子要素には、計算された平均給与が含まれます。

XQueryを使用した表またはビュー・データの問合せ

この項では、XQueryを使用してリレーショナル・データをXMLデータであるかのように問い合せる例について説明します。

例5-5では、Oracle XQuery関数fn:collectionをFLWOR式で使用して、2つのリレーショナル表regionsおよびcountriesを問い合せています。どちらの表も、サンプル・データベース・スキーマHRに属しています。この例ではさらに、SQLスカラー値AsiaがXQuery変数$regionnameに渡されています。どのSQL式でも、評価することによってPASSINGを使用してXQueryに渡す値を生成できます。その場合、値はSQL*Plus変数REGIONにより与えられます。またこの値は、適切なスカラーSQLデータ型(この場合はVARCHAR2(40))にキャストする必要があります。

例5-5 リレーショナル表をXMLとして問い合せる

DEFINE REGION = 'Asia'
SELECT XMLQuery('for $i in fn:collection("oradb:/HR/REGIONS"),
                     $j in fn:collection("oradb:/HR/COUNTRIES")
                   where $i/ROW/REGION_ID = $j/ROW/REGION_ID
                     and $i/ROW/REGION_NAME = $regionname
                   return $j'
                PASSING CAST('&REGION' AS VARCHAR2(40)) AS "regionname"
                RETURNING CONTENT) AS asian_countries
  FROM DUAL;

これによって、次の結果が戻されます。(ここではわかりやすいように、この結果をフォーマット出力しています。)

ASIAN_COUNTRIES
-----------------------------------------
<ROW>
  <COUNTRY_ID>AU</COUNTRY_ID>
  <COUNTRY_NAME>Australia</COUNTRY_NAME>
  <REGION_ID>3</REGION_ID>
</ROW>
<ROW>
  <COUNTRY_ID>CN</COUNTRY_ID>
  <COUNTRY_NAME>China</COUNTRY_NAME>
  <REGION_ID>3</REGION_ID>
</ROW>
<ROW>
  <COUNTRY_ID>HK</COUNTRY_ID>
  <COUNTRY_NAME>HongKong</COUNTRY_NAME>
  <REGION_ID>3</REGION_ID>
</ROW>
<ROW>
  <COUNTRY_ID>IN</COUNTRY_ID>
  <COUNTRY_NAME>India</COUNTRY_NAME>
  <REGION_ID>3</REGION_ID>
</ROW>
<ROW>
  <COUNTRY_ID>JP</COUNTRY_ID>
  <COUNTRY_NAME>Japan</COUNTRY_NAME>
  <REGION_ID>3</REGION_ID>
</ROW>
<ROW>
  <COUNTRY_ID>SG</COUNTRY_ID>
  <COUNTRY_NAME>Singapore</COUNTRY_NAME>
  <REGION_ID>3</REGION_ID>
</ROW>
 
1 row selected.

例5-5では、各種のFLWOR句が次の操作を行っています。

  • forは、fn:collectionのコールにより戻されるXML要素のシーケンスについて反復を実行します。最初のコールでは、各要素はリレーショナル表hr.regionsの行に対応し、変数$iにバインドされます。同様に、fn:collectionの2回目のコールでは、$jは、表hr.countriesの後続する行にバインドされます。regionsおよびcountriesXMLType表ではないため、各表の行に対応する最上位要素はROWです(ラッパー要素)。行要素についての反復は順序付けられていません。

  • whereは両方の表から行をフィルタリングし、各表でregion_idが同一であり(region_idに結合を実行)、region_nameAsiaである行のペアのみを残します。

  • returnは、hr.countries表からの行を、ROWを最上位要素とする、XMLフラグメントを含むXML文書として戻します。

例5-6では、ネストされたFLWOR式でfn:collection を使用して、リレーショナル・データを問い合せています。

例5-6 ネストされたFLWOR問合せでのリレーショナル・データの使用

CONNECT hr
Enter password: password

Connected.

GRANT SELECT ON LOCATIONS TO OE
/
CONNECT oe
Enter password: password

Connected.

SELECT XMLQuery(
         'for $i in fn:collection("oradb:/OE/WAREHOUSES")/ROW
          return <Warehouse id="{$i/WAREHOUSE_ID}">
                   <Location>
                     {for $j in fn:collection("oradb:/HR/LOCATIONS")/ROW
                      where $j/LOCATION_ID eq $i/LOCATION_ID 
                      return ($j/STREET_ADDRESS, $j/CITY, $j/STATE_PROVINCE)}
                   </Location>    
                 </Warehouse>'
         RETURNING CONTENT) FROM DUAL;

この問合せは、ネストされたFLWOR式の使用例です。アクセスするリレーショナル表は、サンプル・データベース・スキーマoeにあるwarehousesと、サンプル・データベース・スキーマHRにあるlocationsです。この例をユーザーoeとして実行するには、最初にユーザーhrとして接続し、ユーザーoeに対して、表locationsSELECT操作を実行する権限を付与する必要があります。

これによって、次の結果が戻されます。(ここではわかりやすいように、この結果をフォーマット出力しています。)

XMLQUERY('FOR$IINFN:COLLECTION("ORADB:/OE/WAREHOUSES")/ROWRETURN<WAREHOUSEID="{$
--------------------------------------------------------------------------------
<Warehouse id="1">
  <Location>
    <STREET_ADDRESS>2014 Jabberwocky Rd</STREET_ADDRESS>
    <CITY>Southlake</CITY>
    <STATE_PROVINCE>Texas</STATE_PROVINCE>
  </Location>
</Warehouse>
<Warehouse id="2">
  <Location>
    <STREET_ADDRESS>2011 Interiors Blvd</STREET_ADDRESS>
    <CITY>South San Francisco</CITY>
    <STATE_PROVINCE>California</STATE_PROVINCE>
  </Location>
</Warehouse>
<Warehouse id="3">
  <Location>
    <STREET_ADDRESS>2007 Zagora St</STREET_ADDRESS>
    <CITY>South Brunswick</CITY>
    <STATE_PROVINCE>New Jersey</STATE_PROVINCE>
  </Location>
</Warehouse>
<Warehouse id="4">
  <Location>
    <STREET_ADDRESS>2004 Charade Rd</STREET_ADDRESS>
    <CITY>Seattle</CITY>
    <STATE_PROVINCE>Washington</STATE_PROVINCE>
  </Location>
</Warehouse>
<Warehouse id="5">
  <Location>
    <STREET_ADDRESS>147 Spadina Ave</STREET_ADDRESS>
    <CITY>Toronto</CITY>
    <STATE_PROVINCE>Ontario</STATE_PROVINCE>
  </Location>
</Warehouse>
<Warehouse id="6">
  <Location>
    <STREET_ADDRESS>12-98 Victoria Street</STREET_ADDRESS>
    <CITY>Sydney</CITY>
    <STATE_PROVINCE>New South Wales</STATE_PROVINCE>
  </Location>
</Warehouse>
<Warehouse id="7">
  <Location>
    <STREET_ADDRESS>Mariano Escobedo 9991</STREET_ADDRESS>
    <CITY>Mexico City</CITY>
    <STATE_PROVINCE>Distrito Federal,</STATE_PROVINCE>
  </Location>
</Warehouse>
<Warehouse id="8">
  <Location>
    <STREET_ADDRESS>40-5-12 Laogianggen</STREET_ADDRESS>
    <CITY>Beijing</CITY>
  </Location>
</Warehouse>
<Warehouse id="9">
  <Location>
    <STREET_ADDRESS>1298 Vileparle (E)</STREET_ADDRESS>
    <CITY>Bombay</CITY>
    <STATE_PROVINCE>Maharashtra</STATE_PROVINCE>
  </Location>
</Warehouse>
 
1 row selected.

例5-6では、各種のFLWOR句が次の操作を行っています。

  • 外側のforfn:collectionにより戻されたXML要素のシーケンスについて反復を実行します。各要素はリレーショナル表oe.warehousesの行に対応していて、変数$iにバインドされています。warehousesXMLType表ではないので、行に対応する最上位の要素はROWとなります。行要素についての反復は順序付けられていません。

  • 内側のforも同様にfn:collectionにより戻されたXML要素のシーケンスについて反復を実行します。各要素はリレーショナル表hr.locationsの行に対応していて、変数$jにバインドされています。

  • whereはタプル($i, $j)をフィルタリングし、location_id の子が、$iおよび$jに対して同じであるタプルのみを残します(location_idに基づいてjoinを実行します)。

  • 内側のreturnは、要素 STREET_ADDRESSCITY、およびSTATE_PROVINCEのXQueryシーケンスを、すべてlocations表のROW要素 $jの子、つまり、locations表の同名の列の値として構成します。

  • 外側のreturnは内側のreturnの結果をLocation要素で囲み、それをさらにWarehouse要素で囲みます。Warehouse要素に対して、値を表warehouseswarehouse_id列から取得したid属性を提供します。


関連項目:

例5-6の実行計画は、例5-15を参照してください。

例5-7では、SQL/XML関数XMLTableは、XQuery問合せの結果を仮想リレーショナル・データに分解するために使用されています。この例で使用されているXQuery式は 例5-6で使用されているものと同一です。XQuery式の評価結果はWarehouse要素のシーケンスです。関数XMLTableは、行がWarehouse要素である仮想リレーショナル表を生成します。正確には、仮想表の各行に対応する疑似列COLUMN_VALUEはXMLフラグメント(XMLType型)で、単一のWarehouse要素を持ちます。

例5-7 XMLTableでリレーショナル表をXMLとして問い合せる

SELECT * 
  FROM XMLTable(
         'for $i in fn:collection("oradb:/OE/WAREHOUSES")/ROW
          return <Warehouse id="{$i/WAREHOUSE_ID}">
                   <Location>
                     {for $j in fn:collection("oradb:/HR/LOCATIONS")/ROW
                      where $j/LOCATION_ID eq $i/LOCATION_ID 
                      return ($j/STREET_ADDRESS, $j/CITY, $j/STATE_PROVINCE)}
                   </Location>
                 </Warehouse>');

これにより例5-6と同じ結果が生成されます。ただし、すべてのWarehouse要素が統合され単一の行に出力されるのでなく、各Warehouse要素が別々の行として出力される点が異なります。

COLUMN_VALUE
--------------------------------------------------------
<Warehouse id="1">
  <Location>
    <STREET_ADDRESS>2014 Jabberwocky Rd</STREET_ADDRESS>
    <CITY>Southlake</CITY>
    <STATE_PROVINCE>Texas</STATE_PROVINCE>
  </Location>
</Warehouse>
<Warehouse id="2">
  <Location>
    <STREET_ADDRESS>2011 Interiors Blvd</STREET_ADDRESS>
    <CITY>South San Francisco</CITY>
    <STATE_PROVINCE>California</STATE_PROVINCE>
  </Location>
</Warehouse>
. . .
 
9 rows selected.

関連項目:

例5-7の実行計画は、例5-16を参照してください。

XQueryのXMLTypeデータとの使用

この項では、XQueryをXMLTypeリレーショナル・データとともに使用する例を紹介します。

例5-8の問合せでは関数XMLQueryPASSING句を使用して、XMLTypewarehouse_specコンテキスト項目としてXQueryに渡します。これにより、領域が80,000を超えるウェアハウス(/Warehouse/ Area > 80000)のそれぞれについてDetails要素が作成されます。

例5-8 XMLQueryでPASSING句を使用してXMLType列を問い合せる

SELECT warehouse_name, 
       XMLQuery(
         'for $i in /Warehouse 
          where  $i/Area > 80000 
          return <Details>
                   <Docks num="{$i/Docks}"/>
                   <Rail>{if ($i/RailAccess = "Y") then "true" else "false"}
                   </Rail>
                 </Details>'
         PASSING warehouse_spec RETURNING CONTENT) big_warehouses
  FROM oe.warehouses;

これによって、次の出力が生成されます。

WAREHOUSE_NAME
--------------
BIG_WAREHOUSES
--------------
Southlake, Texas
 
 
San Francisco
 
 
New Jersey
<Details><Docks num=""></Docks><Rail>false</Rail></Details>
 
Seattle, Washington
<Details><Docks num="3"></Docks><Rail>true</Rail></Details>
 
Toronto
 
 
Sydney
 
 
Mexico City
 
 
Beijing
 
 
Bombay
 
 
9 rows selected.

例5-8では、関数XMLQueryは表warehousesの各行のwarehouse_spec列に適用されます。各FLWOR句は次の操作を実行します。

  • forは列warehouse_spec(渡されたコンテキスト項目)の各行のWarehouse要素について反復を実行します。各要素はそれぞれ$iにバインドされます。反復は順序付けられていません。

  • whereWarehouse要素をフィルタリングして、Area子の値が80,000を超えるもののみを残します。

  • returnDetailsの要素のXQueryシーケンスを構成します。各要素は子要素DocksおよびRailを含みます。構成されたDocks要素のnum属性はWarehouseの子Dockstext()値に設定されます。Railtext()コンテンツは、要素WarehouseRailAccess属性の値に応じて、trueまたはfalseに設定されます。

例5-8SELECT文は、表warehousesの各行に適用されます。XMLQuery式は、XQuery式に一致しない行については空のシーケンスを戻します。New JerseyとSeattleの倉庫のみがXQuery問合せに適合するので、それらの倉庫についてのみ<Details>...</Details>が戻されます。

例5-9はSQL/XML関数XMLTableを使用して、XML Schemaに基づくデータを含むXMLTypeoe.purchaseorderを問い合せます。PASSING句を使用して、XMLTableのXQuery式の引数のコンテキスト項目としてpurchaseorder表を提供します。結果として得られる仮想表の疑似列COLUMN_VALUEは、CostCenter要素が値A10を持ち、User要素が値SMCCAINを持つReference情報を含む、構成された要素A10poを保持します。この問合せは、仮想表とデータベース表purchaseorderの間の結合を実行します。

例5-9 XMLTABLEでXML Schemaに基づくデータを使用する

SELECT xtab.COLUMN_VALUE
  FROM purchaseorder, XMLTable('for $i in /PurchaseOrder
                                where $i/CostCenter eq "A10"
                                  and $i/User eq "SMCCAIN"
                                return <A10po pono="{$i/Reference}"/>'
                               PASSING OBJECT_VALUE) xtab;
 
COLUMN_VALUE
---------------------------------------------------
<A10po pono="SMCCAIN-20021009123336151PDT"></A10po>
<A10po pono="SMCCAIN-20021009123336341PDT"></A10po>
<A10po pono="SMCCAIN-20021009123337173PDT"></A10po>
<A10po pono="SMCCAIN-20021009123335681PDT"></A10po>
<A10po pono="SMCCAIN-20021009123335470PDT"></A10po>
<A10po pono="SMCCAIN-20021009123336972PDT"></A10po>
<A10po pono="SMCCAIN-20021009123336842PDT"></A10po>
<A10po pono="SMCCAIN-20021009123336512PDT"></A10po>
<A10po pono="SMCCAIN-2002100912333894PDT"></A10po>
<A10po pono="SMCCAIN-20021009123337403PDT"></A10po>
 
10 rows selected.

関数XMLTablePASSING句により、XMLTypeOBJECT_VALUEpurchaseorder表に渡され、XPathコンテキストとして使用されます。したがって、XMLTable式はpurchaseorder表に依存します。このため、表purchaseorderは、FROMリストのXMLTable式よりも前に記述する必要があります。これは、データの依存関係が存在する状況では一般的な要件です。


注意:

PASSING 句が、問合せにおいてXMLType表の列の1つを参照している場合、その表は必ず問合せのFROMリストのXMLTable式よりも前に記述する必要があります。これは、XMLTable式がXMLType表に依存しているためです。XMLType表のアクセス行と、XMLTableによってそこから生成された行との間に1対多(1:N)の関係を保証するためには、左側(相関)結合が必要です。

例5-10で得られる結果は例5-9に類似しています。XMLTableのかわりにXMLQueryを使用してoe.purchaseorderを問い合せます。次の2つの例では、XQuery式により戻される空のシーケンスの処理が異なります。例5-9では、これらの空のシーケンスはpurchaseorder表を使用して結合されないため、SQL問合せの結果セットは全体で10行のみとなります。例5-10では、これらの空のシーケンスは、132行が含まれ、それぞれが表purchaseorderの各行に対応するSQL問合せの結果セットの一部となります。10行を除いて行はすべて空で、出力でも空行となります。紙数を節約するために、ここでは空行は省略してあります。

例5-10 XMLQUERYでXML Schemaに基づくデータを使用する

SELECT XMLQuery('for $i in /PurchaseOrder
                 where $i/CostCenter eq "A10"
                   and $i/User eq "SMCCAIN"
                 return <A10po pono="{$i/Reference}"/>'
                PASSING OBJECT_VALUE
                RETURNING CONTENT)
  FROM purchaseorder;
 
XMLQUERY('FOR$IIN/PURCHASEORDERWHERE$I/COSTCENTEREQ"A10"AND$I/USEREQ"SMCCAIN"RET
--------------------------------------------------------------------------------
<A10po pono="SMCCAIN-20021009123336151PDT"></A10po>
<A10po pono="SMCCAIN-20021009123336341PDT"></A10po>
<A10po pono="SMCCAIN-20021009123337173PDT"></A10po>
<A10po pono="SMCCAIN-20021009123335681PDT"></A10po>
<A10po pono="SMCCAIN-20021009123335470PDT"></A10po>
<A10po pono="SMCCAIN-20021009123336972PDT"></A10po>
<A10po pono="SMCCAIN-20021009123336842PDT"></A10po>
<A10po pono="SMCCAIN-20021009123336512PDT"></A10po>
<A10po pono="SMCCAIN-2002100912333894PDT"></A10po>
<A10po pono="SMCCAIN-20021009123337403PDT"></A10po>
 
132 rows selected.

関連項目:

例5-10の実行計画は、例5-17を参照してください。

例5-11では、XMLTablePASSINGおよびCOLUMNSを使用します。XQuery式は最上位のPurchaseOrder要素について反復を実行し、コスト・センターA10を含む発注書に対応するPO要素を構成します。結果のPO要素は続いてXMLTableに渡されて処理されます。

例5-11 XMLTABLEでのPASSINGおよびCOLUMNS句の使用

SELECT xtab.poref, xtab.priority, xtab.contact
  FROM purchaseorder,
       XMLTable('for $i in /PurchaseOrder
                 let $spl := $i/SpecialInstructions
                 where $i/CostCenter eq "A10"
                 return <PO>
                          <Ref>{$i/Reference}</Ref>
                          {if ($spl eq "Next Day Air" or $spl eq "Expedite") then
                             <Type>Fastest</Type>
                           else if ($spl eq "Air Mail") then
                             <Type>Fast</Type>
                           else ()}
                          <Name>{$i/Requestor}</Name>
                        </PO>'
                PASSING OBJECT_VALUE
                COLUMNS poref    VARCHAR2(20) PATH 'Ref',
                        priority VARCHAR2(8)  PATH 'Type' DEFAULT 'Regular',
                        contact  VARCHAR2(20) PATH 'Name') xtab;
 
POREF                PRIORITY CONTACT
-------------------- -------- --------------------
SKING-20021009123336 Fastest  Steven A. King
SMCCAIN-200210091233 Regular  Samuel B. McCain
SMCCAIN-200210091233 Fastest  Samuel B. McCain
JCHEN-20021009123337 Fastest  John Z. Chen
JCHEN-20021009123337 Regular  John Z. Chen
SKING-20021009123337 Regular  Steven A. King
SMCCAIN-200210091233 Regular  Samuel B. McCain
JCHEN-20021009123338 Regular  John Z. Chen
SMCCAIN-200210091233 Regular  Samuel B. McCain
SKING-20021009123335 Regular  Steven X. King
SMCCAIN-200210091233 Regular  Samuel B. McCain
SKING-20021009123336 Regular  Steven A. King
SMCCAIN-200210091233 Fast     Samuel B. McCain
SKING-20021009123336 Fastest  Steven A. King
SKING-20021009123336 Fastest  Steven A. King
SMCCAIN-200210091233 Regular  Samuel B. McCain
JCHEN-20021009123335 Regular  John Z. Chen
SKING-20021009123336 Regular  Steven A. King
JCHEN-20021009123336 Regular  John Z. Chen
SKING-20021009123336 Regular  Steven A. King
SMCCAIN-200210091233 Regular  Samuel B. McCain
SKING-20021009123337 Regular  Steven A. King
SKING-20021009123338 Fastest  Steven A. King
SMCCAIN-200210091233 Regular  Samuel B. McCain
JCHEN-20021009123337 Regular  John Z. Chen
JCHEN-20021009123337 Regular  John Z. Chen
JCHEN-20021009123337 Regular  John Z. Chen
SKING-20021009123337 Regular  Steven A. King
JCHEN-20021009123337 Regular  John Z. Chen
SKING-20021009123337 Regular  Steven A. King
SKING-20021009123337 Regular  Steven A. King
SMCCAIN-200210091233 Fast     Samuel B. McCain
 
32 rows selected.

例5-11では、PurchaseOrderの子から取得したデータは、POの子、RefTypeおよびNameを構成するのに使用されます。Typeのコンテンツは/PurchaseOrder/SpecialInstructionsのコンテンツから取得されますが、SpecialInstructionsのクラスはTypeに対応して異なる方法で分割されます。

関数XMLTableはXQuery評価の結果を、porefpriority、およびcontactの仮想表の3つのVARCHAR2列に分割します。DEFAULT句は、Regularのデフォルトのpriorityを指定するのに使用されます。

例5-12では、SQL/XML関数XMLTableは、XMLTypeコレクション要素LineItemのXMLデータを、仮想表の個別の列に分割するために使用されています。

例5-12 XMLTABLEを使用してXMLコレクション要素をリレーショナル・データに分解する

SELECT lines.lineitem, lines.description, lines.partid,
       lines.unitprice, lines.quantity
  FROM purchaseorder,
       XMLTable('for $i in /PurchaseOrder/LineItems/LineItem
                 where $i/@ItemNumber >= 8
                  and $i/Part/@UnitPrice > 50
                  and $i/Part/@Quantity > 2
                 return $i'
                PASSING OBJECT_VALUE
                COLUMNS lineitem    NUMBER       PATH '@ItemNumber',
                        description VARCHAR2(30) PATH 'Description',
                        partid      NUMBER       PATH 'Part/@Id',
                        unitprice   NUMBER       PATH 'Part/@UnitPrice',
                        quantity    NUMBER       PATH 'Part/@Quantity') lines; 

LINEITEM DESCRIPTION                           PARTID UNITPRICE QUANTITY
-------- ------------------------------ ------------- --------- --------
      11 Orphic Trilogy                   37429148327        80        3
      22 Dreyer Box Set                   37429158425        80        4
      11 Dreyer Box Set                   37429158425        80        3
      16 Dreyer Box Set                   37429158425        80        3
       8 Dreyer Box Set                   37429158425        80        3
      12 Brazil                           37429138526        60        3
      18 Eisenstein: The Sound Years      37429149126        80        4
      24 Dreyer Box Set                   37429158425        80        3
      14 Dreyer Box Set                   37429158425        80        4
      10 Brazil                           37429138526        60        3
      17 Eisenstein: The Sound Years      37429149126        80        3
      16 Orphic Trilogy                   37429148327        80        4
      13 Orphic Trilogy                   37429148327        80        4
      10 Brazil                           37429138526        60        4
      12 Eisenstein: The Sound Years      37429149126        80        3
      12 Dreyer Box Set                   37429158425        80        4
      13 Dreyer Box Set                   37429158425        80        4
 
17 rows selected.

関連項目:


XQueryでのネームスペースの使用

XQuery declare namespace宣言をXQuery式のプロローグで使用して、名前空間の接頭辞を定義することができます。declare default namespaceを使用して、式のデフォルトの名前空間として名前空間を確立できます。

名前空間宣言を記述した行の末尾にセミコロン(;)を置いた場合、SQL*Plusでは、そのセミコロンがSQLの終端文字として解釈されます。SQL*Plusを使用する場合は、この点に注意が必要です。これを避けるには、次のいずれかを実行します。

  • 同じ行のセミコロンの後にテキストを挿入する。

  • 同じ行のセミコロンの後に、(: :)のようなコメントを挿入する。

  • SQL*PlusコマンドSET SQLTERMINATORを使用して、SQLの終端文字の認識を無効にする。

例5-13は、XQuery式の名前空間宣言の使用方法を示しています。

例5-13 XMLQUERYでの名前空間宣言の使用

SELECT XMLQuery('declare namespace e = "http://example.com";
ERROR:
ORA-01756: quoted string not properly terminated
 
                 for $i in doc("/public/empsns.xml")/e:emps/e:emp
SP2-0734: unknown command beginning "for $i in ..." - rest of line ignored.
...

-- This works - do not end the line with ";".
SELECT XMLQuery('declare namespace e = "http://example.com"; for
                     $i in doc("/public/empsns.xml")/e:emps/e:emp
                 let $d := 
                   doc("/public/depts.xml")//dept[deptno=$i/@deptno]/@dname
                 where $i/@salary > 100000
                 order by $i/@empno
                 return <emp ename="{$i/@ename}" dept="{$d}"/>'
                RETURNING CONTENT) FROM DUAL;
 
XMLQUERY('DECLARENAMESPACEE="HTTP://EXAMPLE.COM";FOR$IINDOC("/PUBLIC/EMPSNS.XML"
--------------------------------------------------------------------------------
<emp ename="Jack" dept=""></emp><emp ename="Jill" dept=""></emp>

-- This works too - add a comment after the ";".
SELECT XMLQuery('declare namespace e = "http://example.com";  (: :)
                 for $i in doc("/public/empsns.xml")/e:emps/e:emp
                 let $d := doc("/public/depts.xml")//dept[deptno=$i/@deptno]/@dname
                 where $i/@salary > 100000
                 order by $i/@empno
                 return <emp ename="{$i/@ename}" dept="{$d}"/>'
                RETURNING CONTENT) FROM DUAL;
 
XMLQUERY('DECLARENAMESPACEE="HTTP://EXAMPLE.COM";(::)FOR$IINDOC("/PUBLIC/EMPSNS.
--------------------------------------------------------------------------------
<emp ename="Jack" dept=""></emp><emp ename="Jill" dept=""></emp>
 
1 row selected.

-- This works too - tell SQL*Plus to ignore the ";".
SET SQLTERMINATOR OFF
 
SELECT XMLQuery('declare namespace e = "http://example.com";
                 for $i in doc("/public/empsns.xml")/e:emps/e:emp
                 let $d :=
                   doc("/public/depts.xml")//dept[deptno=$i/@deptno]/@dname
                 where $i/@salary > 100000
                 order by $i/@empno
                 return <emp ename="{$i/@ename}" dept="{$d}"/>'
                RETURNING CONTENT) FROM DUAL
/
 
XMLQUERY('DECLARENAMESPACEE="HTTP://EXAMPLE.COM";FOR$IINDOC("/PUBLIC/EMPSNS.XML"
--------------------------------------------------------------------------------
<emp ename="Jack" dept=""></emp><emp ename="Jill" dept=""></emp>

XQuery名前空間宣言は、XQuery式の外部では無効です。XMLTable式で使用する名前空間接頭辞をXQuery式の外部で宣言するにはXMLNAMESPACES句を使用します。この句はXMLTableのXQuery式の引数でも使用できるため、XQueryプロローグを別個に宣言する必要はありません。

例5-14では、XMLNAMESPACESは名前空間http://example.comに対応する接頭辞eを定義するために使用されます。このネームスペースはCOLUMNS句とXMLTable式のXQuery式で使用されます。

例5-14 XMLTABLEでのXMLNAMESPACES句の使用

SELECT * FROM XMLTable(XMLNAMESPACES ('http://example.com' AS "e"),
                       'for $i in doc("/public/empsns.xml")
                        return $i/e:emps/e:emp'
                       COLUMNS name VARCHAR2(6) PATH '@ename',
                               id   NUMBER      PATH '@empno');

これによって、次の結果が戻されます。

NAME           ID
------ ----------
John            1
Jack            2
Jill            3
 
3 rows selected.

修飾名e:enameおよびe:empnoCOLUMNS句に存在することにより、XMLNAMESPACES句を使用する必要が生じています。そうでなければ、XQuery式のみのためにはプロローグ名前空間宣言(declare namespace e = "http://example.com")で十分です。

XMLTable式で同一の名前空間が使用されているので、デフォルトの名前空間XMLNAMESPACES (DEFAULT 'http://example.com')を使用できます。このため、修飾名$i/e:emps/e:empを、明示的接頭辞を使用せずに$i/emps/empと書いてかまいません。

XQuery用のパフォーマンス・チューニング

XQuery式を使用するSQL問合せは、多くの場合、1つ以上の方法でリライト(最適化)できます。このような最適化は、XML問合せのリライトまたは最適化と呼ばれます。XPath式は、XQuery式の適切なサブセットです。

XPathリライトは、XML問合せリライトのサブセットであり、XPath式を使用する問合せがリライトされます。XPathリライトでは、XMLIndexの最適化と、バイナリXMLのストリーミング評価が行われます。また、構造化記憶域やリレーショナル・データのXMLTypeビューの場合は、基礎となるオブジェクト・リレーショナル形式またはリレーショナル形式の構造へのリライトも行われます。

問合せのチューニングは、SQLのパフォーマンスと同様に、XQueryのパフォーマンスも改善することができます。XQueryのパフォーマンスをチューニングするには、該当するXML記憶域モデルと索引を選択します。

一般のデータベースの問合せと同様に、チューニングが必要かどうかは、問合せの実行計画をチェックして決定します。計画が最適でない場合は、次のマニュアルで個別のチューニング情報を参照してください。

また、次の式は処理コストがかかることがあり、そのため、大量のデータを処理する場合にパフォーマンスにオーバーヘッドが発生する可能性があることに注意してください。

  • 次のOracle SQL関数を使用するSQL式(XPath式引数を受け入れる):

    • appendChildXML(かわりにinsertChildXMLAfterを使用)

    • insertXMLAfter(かわりにinsertChildXMLAfterを使用)

    • insertXMLBefore(かわりにinsertChildXMLBeforeを使用)

  • 次の軸を使用するXQuery式(かわりにforwardおよびdescendentの軸を使用):

    • ancestor

    • ancestor-or-self

    • descendant-or-self

    • following

    • following-sibling

    • namespace

    • parent

    • preceding

    • preceding-sibling

  • ノード・アイデンティティを伴うXQuery式(順序比較演算子<<および>>の使用など)

次の各項では、この章でここまでに示した例の一部に対する実行計画を示し、それがどのように実行されるかを説明します。


関連項目:


ルールベースおよびコストベースのXQueryの最適化

XQuery式を使用する問合せに対しては、使用されているXMLType記憶域モデルや索引付けなどの様々な要因によって、競合する最適化候補が複数あります。

デフォルトでは、Oracle XML DBは、優先順位付きのルール・セットに従って、特定の問合せおよびコンテキストに対して使用する最適化候補を決定します。この動作は、ルールベースのXML問合せのリライトと呼ばれます。

また、Oracle XML DBはコストベースのXML問合せのリライトを使用することもできます。このモードでは、Oracle XML DBは、特定の問合せに対する様々なXML最適化候補のパフォーマンスを評価し、最もパフォーマンスが高いと予測される組合せを選択します。

オプティマイザ・ヒント/*+ COST_XML_QUERY_REWRITE */を使用すると、特定のSQL文に対してコストベースの最適化を強制できます。

リレーショナル・データに関するXQueryの最適化

例5-15は、XMLとしてアクセスされるリレーショナル・データに対するXMLQueryの最適化を示します。例5-16に、同じコンテキストにおけるXMLTableの最適化を示します。

例5-15 リレーショナル・データに関するXMLQueryの最適化

例5-6の問合せと、その実行計画をもう一度見てみます。この例は、問合せが最適化されていることを示しています。

SELECT XMLQuery(
         'for $i in fn:collection("oradb:/OE/WAREHOUSES")/ROW
          return <Warehouse id="{$i/WAREHOUSE_ID}">
                   <Location>
                     {for $j in fn:collection("oradb:/HR/LOCATIONS")/ROW
                      where $j/LOCATION_ID eq $i/LOCATION_ID 
                      return ($j/STREET_ADDRESS, $j/CITY, $j/STATE_PROVINCE)}
                   </Location>    
                 </Warehouse>'
         RETURNING CONTENT) FROM DUAL;
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------
Plan hash value: 3341889589

-------------------------------------------------------------------------------------------
| Id  | Operation                    | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |            |     1 |       |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE              |            |     1 |    41 |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| LOCATIONS  |     1 |    41 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | LOC_ID_PK  |     1 |       |     0   (0)| 00:00:01 |
|   4 |  SORT AGGREGATE              |            |     1 |     6 |            |          |
|   5 |   TABLE ACCESS FULL          | WAREHOUSES |     9 |    54 |     2   (0)| 00:00:01 |
|   6 |  FAST DUAL                   |            |     1 |       |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   3 - access("LOCATION_ID"=:B1)
 
18 rows selected.

例5-16 リレーショナル・データに関するXMLTableの最適化

例5-7の問合せと、その実行計画をもう一度見てみます。この例は、問合せが最適化されていることを示しています。

SELECT * 
  FROM XMLTable(
         'for $i in fn:collection("oradb:/OE/WAREHOUSES")/ROW
          return <Warehouse id="{$i/WAREHOUSE_ID}">
                   <Location>
                     {for $j in fn:collection("oradb:/HR/LOCATIONS")/ROW
                      where $j/LOCATION_ID eq $i/LOCATION_ID 
                      return ($j/STREET_ADDRESS, $j/CITY, $j/STATE_PROVINCE)}
                   </Location>
                 </Warehouse>');
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------
Plan hash value: 1021775546
 
-------------------------------------------------------------------------------------------
| Id  | Operation                    | Name       | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |            |     9 |    54 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE              |            |     1 |    41 |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| LOCATIONS  |     1 |    41 |     1   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | LOC_ID_PK  |     1 |       |     0   (0)| 00:00:01 |
|   4 |  TABLE ACCESS FULL           | WAREHOUSES |     9 |    54 |     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   3 - access("LOCATION_ID"=:B1)
 
16 rows selected.

XML SchemaベースのXMLTypeデータに関するXQueryの最適化

例5-17に、XML Schemaに基づくXMLType表に関するXMLQueryの最適化を示します。例5-18に、同じコンテキストにおけるXMLTableの最適化を示します。

例5-17 XML Schemaに基づくXMLTypeデータを含むXMLQueryの最適化

例5-10の問合せと、その実行計画をもう一度見てみます。この例は、問合せが最適化されていることを示しています。

SELECT XMLQuery('for $i in /PurchaseOrder
                 where $i/CostCenter eq "A10"
                   and $i/User eq "SMCCAIN"
                 return <A10po pono="{$i/Reference}"/>'
                PASSING OBJECT_VALUE
                RETURNING CONTENT)
  FROM purchaseorder;
 
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------
Plan hash value: 3611789148
 
-------------------------------------------------------------------------------------
| Id  | Operation           | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |               |     1 |   530 |     5   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE     |               |     1 |       |            |          |
|*  2 |   FILTER            |               |       |       |            |          |
|   3 |    FAST DUAL        |               |     1 |       |     2   (0)| 00:00:01 |
|*  4 |    TABLE ACCESS FULL| PURCHASEORDER |     1 |   530 |     5   (0)| 00:00:01 |
-------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - filter(:B1='SMCCAIN' AND :B2='A10')
   4 - filter(SYS_CHECKACL("ACLOID","OWNERID",xmltype('<privilege
              xmlns="http://xmlns.oracle.com/xdb/acl.xsd"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.oracle.com/xdb/acl.xsd
              http://xmlns.oracle.com/xdb/acl.xsd DAV:http://xmlns.oracle.com/xdb/dav.xsd">
              <read-properties/><read-contents/></privilege>'))=1)
 
22 rows selected.

例5-18 XML Schemaに基づくXMLTypeデータを含むXMLTableの最適化

例5-12の問合せと、その実行計画をもう一度見てみます。この例は、問合せが最適化されていることを示しています。XQueryの結果は生成されません。結果セット全体を生成するにはXMLのコレクション要素LineItemの基礎となる記憶域の列が使用されます。

SELECT lines.lineitem, lines.description, lines.partid,
       lines.unitprice, lines.quantity
  FROM purchaseorder,
       XMLTable('for $i in /PurchaseOrder/LineItems/LineItem
                 where $i/@ItemNumber >= 8
                  and $i/Part/@UnitPrice > 50
                  and $i/Part/@Quantity > 2
                 return $i'
                PASSING OBJECT_VALUE
                COLUMNS lineitem    NUMBER       PATH '@ItemNumber',
                        description VARCHAR2(30) PATH 'Description',
                        partid      NUMBER       PATH 'Part/@Id',
                        unitprice   NUMBER       PATH 'Part/@UnitPrice',
                        quantity    NUMBER       PATH 'Part/@Quantity') lines;
 
-----------------------------------------------------------------------------------------------
| Id  | Operation                    | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                |     4 |   384 |     7   (0)| 00:00:01 |
|   1 |  NESTED LOOPS                |                |       |       |            |          |
|   2 |   NESTED LOOPS               |                |     4 |   384 |     7   (0)| 00:00:01 |
|*  3 |    TABLE ACCESS FULL         | PURCHASEORDER  |     1 |    37 |     5   (0)| 00:00:01 |
|*  4 |    INDEX RANGE SCAN          | SYS_C005478    |    17 |       |     1   (0)| 00:00:01 |
|*  5 |   TABLE ACCESS BY INDEX ROWID| LINEITEM_TABLE |     3 |   177 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   3 - filter(SYS_CHECKACL("ACLOID","OWNERID",xmltype('<privilege
              xmlns="http://xmlns.oracle.com/xdb/acl.xsd"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.oracle.com/xdb/acl.xsd
              http://xmlns.oracle.com/xdb/acl.xsd DAV:http://xmlns.oracle.com/xdb/dav.xsd"><read-prop
              erties/><read-contents/></privilege>'))=1)
   4 - access("NESTED_TABLE_ID"="PURCHASEORDER"."SYS_NC0003400035$")
   5 - filter("SYS_NC00013$">50 AND "SYS_NC00012$">2 AND "ITEMNUMBER">=8 AND
              "SYS_NC_TYPEID$" IS NOT NULL)
 
25 rows selected.

この例は、表oe.purchaseorderを完全に検索します。それぞれの発注文書について、XMLTable式が評価されます。purchaseorder表でなくXMLTable式にSQL問合せの実行をまかせる方が効率的です。

XQuery式はリレーショナル式にリライトされていますが、基礎となるリレーショナル・データに基づいて索引を作成することによって最適化を改善できます。この問合せは、純粋なSQL問合せを最適化する場合と同じ方法で最適化できます。これは、Oracle XML DBのXQueryには常にあてはまります。SQLで使用する最適化テクニックをそのまま使用できます。

コレクション要素LineItemUnitPrice属性は、適切な索引ターゲットです。適用されるXMLスキーマが、Ordered Collection Table(OCT)を使用してLineItem要素を格納することを指定しています。

ただし、このOCTの名前は、XML発注書がXML Schemaに基づくデータとして分解されたときに、Oracle XML DBにより生成されます。サンプル・データベース・スキーマHRの表purchaseorderを使用するかわりに、プロパティとデータが同じで、OCTにわかりやすい名前が付いた新しいpurchaseorder表を(異なるデータベース・スキーマに)手動で作成します。その手順は、例3-13を参照してください。

例3-13と同様にpurchaseorder表が作成されたと仮定すると、次の文により適切な索引が作成されます。

CREATE INDEX unitprice_index ON lineitem_table("PART"."UNITPRICE");

この索引が定義されている場合、例5-12の問合せにより、XMLTable式が全体の評価を実行することを示す実行結果が結果として得られます。

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------
Plan hash value: 1578014525
 
----------------------------------------------------------------------------------------
| Id  | Operation          | Name              | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                   |     3 |   624 |     8   (0)| 00:00:01 |
|   1 |  NESTED LOOPS      |                   |     3 |   624 |     8   (0)| 00:00:01 |
|*  2 |   INDEX UNIQUE SCAN| SYS_IOT_TOP_49323 |     3 |   564 |     5   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN| UNITPRICE_INDEX   |    20 |       |     2   (0)| 00:00:01 |
|*  4 |   INDEX UNIQUE SCAN| SYS_C004411       |     1 |       |     0   (0)| 00:00:01 |
----------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
---------------------------------------------------
 
   2 - access("SYS_NC00013$">50)
       filter("ITEMNUMBER">=8 AND "SYS_NC00012$">2)
   3 - access("SYS_NC00013$">50)
   4 - access("NESTED_TABLE_ID"="PURCHASEORDER"."SYS_NC0003400035$")
 
Note
-----
   - dynamic sampling used for this statement
 
23 rows selected.

XQueryの最適化の診断: XMLOptimizationCheck

SQLコードの実行計画を調べて、XQueryの最適化が行われるか、計画が部分的に最適化されるかを判断できます。後者の場合は、計画の直後に次のような注記が表示されます。

Unoptimized XML construct detected (enable XMLOptimizationCheck
for more information)

また、実行計画の出力をオプティマイザ・ヒントNO_XML_QUERY_REWRITEの後に表示される計画の出力と比較することもできます。これによってXQueryの最適化がオフになります。

さらに、SQL*PlusのSETコマンドでシステム変数XMLOptimizationCheckを使用して、SQLのXML診断能力モードをオンにすることができます。

SET XMLOptimizationCheck ON

このモードがオンの場合、XQuery最適化の実行計画が自動的にチェックされ、計画が部分的な最適化の場合は、エラーが発生して診断情報がトレース・ファイルに書き込まれ、どの演算子が書きなおされていないのかが示されます。

XMLOptimizationCheckの主な利点は、潜在的な問題がただちに明らかになることです。このため、常にこのモードをオンにしておくのが望ましいと言えます。そして、何らかの理由でアプリケーションやデータベースに変更が生じたため、SQL操作で書き直しができない場合、原因に気がつかないうちにパフォーマンスが低下するかわりに実行が停止します。


注意:

  • レベル8192(0x2000)のイベント19027を使用すると、特定の式がリライトされない理由を示すトレースをダンプできます。

  • XMLOptimizationCheckは、Oracle Database 11gリリース2(11.2.0.2)以前は利用できませんでした。旧リリースのユーザーは、イベント19201を直接操作して、XQueryの最適化情報を取得していました。



関連項目:

オプティマイザ・ヒントNO_XML_QUERY_REWRITEの詳細は、「XMLIndexの使用の無効化」を参照してください。

リポジトリのデータに対するfn:docおよびfn:collectionのパフォーマンスの向上

Oracle XML DBでは、XQuery関数fn:docおよびfn:collectionを使用して、Oracle XML DBリポジトリ内の文書やコレクションを参照できます。リポジトリのXMLTypeデータがオブジェクト・リレーショナル形式またはバイナリXML形式で格納されている場合、fn:docおよびfn:collectionを使用する問合せは関数として評価されます。つまり、これらは基礎となる記憶域表に直接アクセスできるように最適化されていません。

こうした問合せのパフォーマンスを向上するには、問い合せるリポジトリ・データを保持する実際のデータベースの表にそれらをリンクする必要があります。これを行うには、次のいずれかの方法を実行します。

  • RESOURCE_VIEWビューを、データを保持するXMLType表と結合し、XQuery関数fn:docおよびfn:collectionのかわりに、Oracle SQL関数equals_pathおよびunder_pathをそれぞれ使用します。これらのSQL関数は、パフォーマンスに優れた方法でリポジトリ・リソースを参照します。

  • Oracle XQuery拡張式プラグマora:defaultTableを使用します。

どちらの方法を使用しても結果は同じです。XQueryの標準関数fn:docfn:collectionを引き続き使用できるほか、コードが簡略化されるため、ora:defaultTableプラグマの使用をお薦めします。

この項の例で、これらの2つの方法について説明しています。

fn:docとfn:collectionにかわるequals_pathおよびunder_pathの使用

SQL関数equals_pathおよびunder_pathは、それぞれ指定したリポジトリ・パスにあるリソースを参照します。例5-19および例5-20に、関数fn:docおよびequals_pathでのこの処理を示します。関数fn:collectionおよびunder_pathが同じように処理されます。

例5-19 fn:docを使用した、最適化されていないリポジトリの問合せ

SELECT XMLQuery('let $val :=
                     fn:doc("/home/OE/PurchaseOrders/2002/Sep/VJONES-20021009123337583PDT.xml")
                     /PurchaseOrder/LineItems/LineItem[@ItemNumber =19]
                 return $val' RETURNING CONTENT)
  FROM DUAL;

例5-20 EQUALS_PATHを使用した、最適化されたリポジトリの問合せ

SELECT XMLQuery('let $val := $DOC/PurchaseOrder/LineItems/LineItem[@ItemNumber = 19]
                 return $val' PASSING OBJECT_VALUE AS "DOC" RETURNING CONTENT)
  FROM RESOURCE_VIEW rv, purchaseorder p
  WHERE ref(p) = XMLCast(XMLQuery('declare default element namespace 
                                   "http://xmlns.oracle.com/xdb/XDBResource.xsd"; (: :)
                                   fn:dataFoot 6 (/Resource/XMLRef)' PASSING rv.RES RETURNING CONTENT)
                         AS REF XMLType)
    AND equals_path(rv.RES, '/home/OE/PurchaseOrders/2002/Sep/VJONES-20021009123337583PDT.xml')
        = 1;

Oracle XQueryプラグマora:defaultTableの使用

Oracle XQuery拡張式プラグマora:defaultTableを使用すると、問い合せるリポジトリ・データを格納するデフォルトの表を指定できます。問合せは、デフォルトのテーブルをRESOURCE_VIEWビューに自動的に結合し、XQuery関数fn:docfn:collectionのかわりに、Oracle SQL関数equals_pathおよびunder_pathを使用するようにリライトされます。このため結果は、手動で問合せのコードを記述して、明示的な結合およびequals_pathunder_pathを使用する場合と同じです。例5-21に、この詳細を説明します。問合せが自動的にリライトされ、例5-20のようになります。

例5-21 Oracle XQueryプラグマora:defaultTableを使用したリポジトリの問合せ

SELECT XMLQuery('for $doc in (#ora:defaultTable PURCHASEORDER #)
                             {fn:doc("/home/OE/PurchaseOrders/2002/Sep/VJONES-20021009123337583PDT.xml")}
                   let $val := $doc/PurchaseOrder/LineItems/LineItem[@ItemNumber = 19]
                     return $val}'
                RETURNING CONTENT)
  FROM DUAL;

範囲を明確にするため、プラグマora:defaultTableを、大きい式ではなく適切な文書やコレクションの式、fn:docまたはfn:collectionに直接適用することをお薦めします。

Oracle XML DBにおけるXQuery静的型チェック

Oracle XML DBはすべてのXQuery式を型チェックします。しかし、実行時の型チェックはコストがかかることがあります。最適化技法として、指定された問合せに対してコンパイル時に十分な静的型情報を利用できる場合は常に、Oracle XML DBはその問合せの静的な(コンパイル時)型チェックを行います。指定された問合せに対してコンパイル時に十分な静的型情報を利用できない場合は、Oracle XML DBはその問合せの動的(実行時)型チェックを使用します。

静的型チェックでは、コンパイル時にエラーが発生するので、実行時間を節約できることがあります。静的型チェック・エラーには、データ型エラーと、XML Schemaの観点から無効であるXPath式の使用の両方を含みます。

コンパイル時に十分な静的型情報を提供する一般的な方法には、次の方法があります。

  • リレーショナル・データに関してXQueryとfn:docまたはfn:collectionを使用。

  • XQueryを使用して、問合せコンパイル時にXML Schema情報を利用できるXMLType表、列またはビューを問い合せます。

この項では、静的型チェックの有効性と、型情報を通信するこれら2つの手段の使用方法を示す例を紹介します。

fn:collectionおよびURIスキームoradbによってその場で生成されるXMLデータは、ROWを最上位の要素に持ちますが、例5-22の問合せには、ROWのラッパー要素が欠けています。この脱落により、問合せのコンパイル時エラーが発生します。このようにfn:collectionoradbによりリレーショナル・データをラップし忘れる誤りはよくあることですが、静的型チェックがないと、診断が困難な場合があります。例5-5に正しいコードを示します。

例5-22 XQuery式の静的型チェック: oradb URIスキーム

-- This produces a static-type-check error, because "ROW" is missing.
SELECT XMLQuery('for $i in fn:collection("oradb:/HR/REGIONS"),
                     $j in fn:collection("oradb:/HR/COUNTRIES")
                 where $i/REGION_ID = $j/REGION_ID and $i/REGION_NAME = "Asia"
                 return $j'
                RETURNING CONTENT) AS asian_countries
  FROM DUAL;
SELECT XMLQuery('for $i in fn:collection("oradb:/HR/REGIONS"),
*
ERROR at line 1:
ORA-19276: XPST0005 - XPath step specifies an invalid element/attribute name:
(REGION_ID)

例5-23では、XQueryの静的型チェックにより、XPath式とそのターゲットXML Schemaに基づくデータの不一致を検出します。要素CostCenterが、ここではcostcenterと誤ったスペルになっています(XQueryおよびXPathは大文字/小文字を区別します)。例5-11に正しいコードを示します。

例5-23 XQuery式の静的型チェック: スキーマベースのXML

-- This results in a static-type-check error: CostCenter is not the right case.
SELECT xtab.poref, xtab.usr, xtab.requestor
  FROM purchaseorder,
       XMLTable('for $i in /PurchaseOrder where $i/costcenter eq "A10" return $i'
                PASSING OBJECT_VALUE
                COLUMNS poref     VARCHAR2(20) PATH 'Reference',
                        usr       VARCHAR2(20) PATH 'User' DEFAULT 'Unknown',
                        requestor VARCHAR2(20) PATH 'Requestor') xtab;
  FROM purchaseorder,
       *
ERROR at line 2:
ORA-19276: XPST0005 - XPath step specifies an invalid element/attribute name:
(costcenter)

SQL*Plus XQUERYコマンド

例5-24は、XQuery式の前にSQL*PlusコマンドXQUERYを付け、式の後にスラッシュ(/)を単独で付けることにより、SQL*PlusコマンドラインでXQuery式を直接入力する方法を示します。Oracle Databaseでは、このコマンドで送信されたXQuery式を、SQL/XML関数XMLQueryおよびXMLTable内のXQuery式と同様に処理します。実行は同一で、同じ最適化を使用します。

例5-24 SQL*Plus XQUERYコマンドの使用

SQL> XQUERY for $i in fn:collection("oradb:/HR/DEPARTMENTS")
  2  where $i/ROW/DEPARTMENT_ID < 50
  3  return $i
  4  /
 
Result Sequence
--------------------------------------------------------------------------------
<ROW><DEPARTMENT_ID>10</DEPARTMENT_ID><DEPARTMENT_NAME>Administration</DEPARTMEN
T_NAME><MANAGER_ID>200</MANAGER_ID><LOCATION_ID>1700</LOCATION_ID></ROW>
 
<ROW><DEPARTMENT_ID>20</DEPARTMENT_ID><DEPARTMENT_NAME>Marketing</DEPARTMENT_NAM
E><MANAGER_ID>201</MANAGER_ID><LOCATION_ID>1800</LOCATION_ID></ROW>
 
<ROW><DEPARTMENT_ID>30</DEPARTMENT_ID><DEPARTMENT_NAME>Purchasing</DEPARTMENT_NA
ME><MANAGER_ID>114</MANAGER_ID><LOCATION_ID>1700</LOCATION_ID></ROW>
 
<ROW><DEPARTMENT_ID>40</DEPARTMENT_ID><DEPARTMENT_NAME>Human Resources</DEPARTME
NT_NAME><MANAGER_ID>203</MANAGER_ID><LOCATION_ID>2400</LOCATION_ID></ROW>

XQueryに固有の設定で使用できるSQL*Plus SETコマンドもいくつかあります。現在の設定を参照するにはSHOW XQUERYを使用します。

  • SET XQUERY BASEURI: XQUERYのベースURIを設定します。XQuery式内のURIは、このURIに相対的です。

  • SET XQUERY CONTEXT: 以降のXQUERY評価で使用するコンテキスト項目を指定します。


関連項目:

『SQL*Plusユーザーズ・ガイドおよびリファレンス』

XQueryの、PL/SQL、JDBC、およびODP.NETとの使用

この章の前項で、SQLからXQueryを呼び出す方法を示しました。この項では、XQueryを、PL/SQL、JDBC、およびOracle Data Provider for .NET(ODP.NET)用のOracle APIとともに使用する例を示します。

例5-25は、XQueryをPL/SQLとともに使用する方法、特に、XMLQueryPASSING句を使用して動的変数をXQuery式にバインドする方法を示します。バインド変数:1および:2は、PL/SQLバインド変数nbitemsおよびpartidに、それぞれバインドされます。その後、それぞれXQuery変数itemnoおよびidとしてXQueryに渡されます。

例5-25 XQueryをPL/SQLとともに使用する

DECLARE
  sql_stmt VARCHAR2(2000); -- Dynamic SQL statement to execute
  nbitems  NUMBER := 3; -- Number of items
  partid   VARCHAR2(20):= '715515009058'; -- Part ID
  result   XMLType;
  doc      DBMS_XMLDOM.DOMDocument;
  ndoc     DBMS_XMLDOM.DOMNode;
  buf      VARCHAR2(20000);
BEGIN
  sql_stmt :=
    'SELECT XMLQuery(
              ''for $i in fn:collection("oradb:/OE/PURCHASEORDER") ' ||
               'where count($i/PurchaseOrder/LineItems/LineItem) = $itemno ' ||
                 'and $i/PurchaseOrder/LineItems/LineItem/Part/@Id = $id ' ||
               'return $i/PurchaseOrder/LineItems'' ' ||
              'PASSING :1 AS "itemno", :2 AS "id" ' ||
              'RETURNING CONTENT) FROM DUAL';
 
  EXECUTE IMMEDIATE sql_stmt INTO result USING nbitems, partid;
  doc  := DBMS_XMLDOM.newDOMDocument(result);
  ndoc := DBMS_XMLDOM.makeNode(doc);
  DBMS_XMLDOM.writeToBuffer(ndoc, buf);
  DBMS_OUTPUT.put_line(buf);
END;
/

これによって、次の出力が生成されます。

<LineItems>
  <LineItem ItemNumber="1">
    <Description>Samurai 2: Duel at Ichijoji Temple</Description>
    <Part Id="37429125526" UnitPrice="29.95" Quantity="3"/>
  </LineItem>
  <LineItem ItemNumber="2">
    <Description>The Red Shoes</Description>
    <Part Id="37429128220" UnitPrice="39.95" Quantity="4"/>
  </LineItem>
  <LineItem ItemNumber="3">
    <Description>A Night to Remember</Description>
    <Part Id="715515009058" UnitPrice="39.95" Quantity="1"/>
  </LineItem>
</LineItems>
<LineItems>
  <LineItem ItemNumber="1">
    <Description>A Night to Remember</Description>
    <Part Id="715515009058" UnitPrice="39.95" Quantity="2"/>
  </LineItem>
  <LineItem ItemNumber="2">
    <Description>The Unbearable Lightness Of Being</Description>
    <Part Id="37429140222" UnitPrice="29.95" Quantity="2"/>
  </LineItem>
  <LineItem ItemNumber="3">
    <Description>Sisters</Description>
    <Part Id="715515011020" UnitPrice="29.95" Quantity="4"/>
  </LineItem>
</LineItems>

PL/SQL procedure successfully completed.

例5-26は、XQueryをJDBCとともに使用して、変数をその位置によってSQL/XML関数XMLTablePASSING句にバインドします。

例5-26 XQueryをJDBCとともに使用する

import java.sql.*;
import oracle.sql.*;
import oracle.jdbc.*;
import oracle.xdb.XMLType; 
import java.util.*;
 
public class QueryBindByPos
{
  public static void main(String[] args) throws Exception, SQLException
  {
    System.out.println("*** JDBC Access of XQuery using Bind Variables ***");
    DriverManager.registerDriver(new oracle.jdbc.driver.OracleDriver());
    OracleConnection conn
      = (OracleConnection)
        DriverManager.getConnection("jdbc:oracle:oci8:@localhost:1521:ora11gR1", "oe", "oe");
    String xqString
      = "SELECT COLUMN_VALUE" +
          "FROM XMLTable('for $i in fn:collection(\"oradb:/OE/PURCHASEORDER\") " +
                         "where $i/PurchaseOrder/Reference= $ref " +
                         "return $i/PurchaseOrder/LineItems' " +
                        "PASSING ? AS \"ref\")";
    OraclePreparedStatement stmt = (OraclePreparedStatement)conn.prepareStatement(xqString);
    String refString = "EABEL-20021009123336251PDT"; // Set the filter value
    stmt.setString(1, refString); // Bind the string
    ResultSet rs = stmt.executeQuery();
    while (rs.next())
    {
       XMLType desc = (XMLType) rs.getObject(1);
       System.out.println("LineItem Description: " + desc.getStringVal());
       desc.close();
    }
    rs.close();
    stmt.close();
  }
}

これによって、次の出力が生成されます。

*** JDBC Access of Database XQuery with Bind Variables ***
LineItem Description: Samurai 2: Duel at Ichijoji Temple
LineItem Description: The Red Shoes
LineItem Description: A Night to Remember

例5-27は、XQueryをODP.NETおよびC#言語とともに使用する方法を示します。C#の入力パラメータ:nbitemsおよび:partidは、それぞれXQuery変数itemnoおよびidとしてXQueryに渡されます。

例5-27 XQueryをODP.NETおよびC#とともに使用する

using System;
using System.Data;
using System.Text;
using System.IO;
using System.Xml;
using Oracle.DataAccess.Client;
using Oracle.DataAccess.Types;
 
namespace XQuery
{
  /// <summary>
  /// Demonstrates how to bind variables for XQuery calls
  /// </summary>
  class XQuery
  {
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    static void Main(string[] args)
    {
      int rows = 0;
      StreamReader sr = null;
 
      // Create the connection.
      string constr = "User Id=oe;Password=***********;Data Source=ora11gr2"; // Replace with real password.
      OracleConnection con = new OracleConnection(constr);
      con.Open();
 
      // Create the command.
      OracleCommand cmd = new OracleCommand("", con);
 
      // Set the XML command type to query.
      cmd.CommandType   = CommandType.Text;
        
      // Create the SQL query with the XQuery expression.
      StringBuilder blr = new StringBuilder();
      blr.Append("SELECT COLUMN_VALUE FROM XMLTable");
      blr.Append("(\'for $i in fn:collection(\"oradb:/OE/PURCHASEORDER\") ");
      blr.Append("   where count($i/PurchaseOrder/LineItems/LineItem) = $itemno ");
      blr.Append("      and $i/PurchaseOrder/LineItems/LineItem/Part/@Id = $id ");
      blr.Append("   return $i/PurchaseOrder/LineItems\' ");
      blr.Append("  PASSING :nbitems AS \"itemno\", :partid AS \"id\")");
 
      cmd.CommandText = blr.ToString();
      cmd.Parameters.Add(":nbitems", OracleDbType.Int16, 3, ParameterDirection.Input);
      cmd.Parameters.Add(":partid", OracleDbType.Varchar2, "715515009058", ParameterDirection.Input);
 
      // Get the XML document as an XmlReader.
      OracleDataReader dr = cmd.ExecuteReader();
      dr.Read();
 
      // Get the XMLType column as an OracleXmlType
      OracleXmlType xml = dr.GetOracleXmlType(0);
 
      // Print the XML data in the OracleXmlType object
      Console.WriteLine(xml.Value);
      xml.Dispose();
 
      // Clean up.
      cmd.Dispose();
      con.Close();
      con.Dispose();
    }
  }
}

これによって、次の出力が生成されます。

<LineItems>
  <LineItem ItemNumber="1">
    <Description>Samurai 2: Duel at Ichijoji Temple</Description>
    <Part Id="37429125526" UnitPrice="29.95" Quantity="3"/>
  </LineItem>
  <LineItem ItemNumber="2">
    <Description>The Red Shoes</Description>
    <Part Id="37429128220" UnitPrice="39.95" Quantity="4"/>
  </LineItem>
  <LineItem ItemNumber="3">
    <Description>A Night to Remember</Description>
    <Part Id="715515009058" UnitPrice="39.95" Quantity="1"/>
  </LineItem>
</LineItems>

Oracle XML DBでのXQueryサポート

この項では、XQuery言語のためのOracle XML DBについて説明します。

XQueryとSQLのサポート

Oracle XML DBのXQuery言語サポートは、リレーショナル記憶域の使用範囲とXMLデータの問合せの使用範囲のベスト・フィットの実現を目指しています。つまり、Oracle XML DBは一般的なXQuery実装ですが、それと同時に、リレーショナル問合せとXML問合せの連携動作に特に注意して設計されています。

この項では、Oracle XML DBのXQuery実装の個別のプロパティについて説明します。XQuery標準は、言語処理の一部の特性について、実装により定義されるのか、実装に依存するのかを明示的にコール・アウトしています。また、XQuery標準で規定されているが、Oracle XML DBでサポートされていない機能もいくつかあります。

XQuery標準で指定された実装の選択肢

XQuery仕様では、言語処理の次の点に関しては実装により定義するように指定されています。

  • 暗黙的タイムゾーン・サポート: Oracle XML DBでは、暗黙的タイムゾーンを常にZと仮定しています。タイムゾーンのないxs:datexs:timeおよびxs:datetimeのインスタンスは、自動的にUTCに変換されます。

Oracle XML DBでサポートされていないXQuery機能

XQuery標準で規定されている次の機能は、Oracle XML DBではサポートされていません。

  • copy-namespacesモード: Oracle XML DBでcopy-namespaces宣言についてサポートされるのは、preserveinheritのみです。既存の要素ノードが要素コンストラクタまたは文書コンストラクタによりコピーされた場合、元の要素の範囲にあるすべてのネームスペースはコピー内に保持されます。そうでない場合は、コピーされたノードは構築されたノードの範囲内にあるすべてのネームスペースを継承します。no-preserveまたはno-inheritを指定するとエラーが発生します。

  • バージョン・エンコーディング: Oracle XML DBでは、バージョン宣言の中のオプションのエンコーディング宣言はサポートされません。つまり、(encoding an-encoding)を宣言xquery version a-version;の中に含むことはできません。特に、問合せで使用するエンコーディングは指定できません。エンコーディング宣言が含まれるとエラーが発生します。

  • xml:id: Oracle XML DBでは、xml:idの使用はサポートされません。xml:idを使用するとエラーが発生します。

  • XQueryプロローグのデフォルト照合宣言

  • XQueryプロローグの境界空間宣言

  • XQueryデータ型xs:duration。かわりにxs:yearMonthDurationまたはxs:DayTimeDurationを使用します。

XQueryのオプション機能

XQuery標準で規定されている次のオプション機能は、Oracle XML DBではサポートされていません。

  • スキーマ検証機能

  • モジュール機能

XQueryの関数と演算子のサポート

Oracle XML DBでは、XQuery 1.0およびXPath 2.0の関数および演算子の最新の仕様に含まれるXQueryの関数と演算子がすべてサポートされていますが、次の例外があります。次のものはサポートされていません

  • XQueryの正規表現関数(fn:matchesfn:replaceおよびfn:tokenize)。これらのかわりに、Oracle XQuery関数ora:matchesora:replaceおよびora:tokenizeをそれぞれ使用してください。

  • 関数fn:idおよびfn:idref

  • 引数のない関数fn:collection

  • XQuery関数のオプションの照合パラメータ。

XQuery関数fn:doc、fn:collectionおよびfn:doc-available

Oracle XML DBでは、Oracle XML DBリポジトリにあるすべてのリソースについて、XQuery関数fn:docfn:collectionおよびfn:doc-availableがサポートされています。

関数fn:docはURI引数によりターゲットとされているリポジトリのファイル・リソースを戻します。このリソースは整形式のXMLデータのファイルにしてください。関数fn:collectionも同様ですが、リポジトリのフォルダ・リソースに対して機能します(フォルダ内の各ファイルには整形式のXMLデータが含まれている必要があります)。

Oracle URIスキームoradbとともに使用すると、fn:collectionは既存のリレーショナル・データからその場で派生した、リポジトリにないXMLデータを戻すことができます。

XQuery関数fn:collectionは、URIスキームoradbとともに使用した場合、ターゲットの表やビュー、列が存在しないと、エラーが発生します。関数fn:docfn:collectionでは、引数として引き渡されたリポジトリのリソースが見つからない場合、エラーは発生しません。かわりに、空のシーケンスが戻されます。

任意の文書が存在するかどうかは、XQuery関数fn:doc-availableを使用して判断できます。文書の引数が存在する場合はtrue、存在しなければfalseがそれぞれ戻されます。


関連項目:

XQueryの関数と演算子の定義についてはhttp://www.w3.org



脚注の凡例

脚注1: 戻り値は、通常と同様、シーケンスです。ただしXQueryでは、項目が1つのシーケンスはその項目自身と等価です。この場合、その単独の項目はブール値です。
脚注2: 名前空間の接頭辞xsは、XML Schemaの名前空間http://www.w3.org/2001/XMLSchemaであらかじめ定義されています。
脚注3: ここでは、疑問符(?)は0回または1回出現することを示すインジケータで、引数が空のシーケンスである場合もあります。「XQuery式」を参照してください。
脚注4: ここでは、疑問符(?)は0回または1回出現することを示すインジケータで、引数が空のシーケンスである場合もあります。「XQuery式」を参照してください。
脚注5: ここでは、疑問符(?)は0回または1回出現することを示すインジケータで、引数が空のシーケンスである場合もあります。「XQuery式」を参照してください。
脚注6: XQuery関数fn:dataは、その引数の分解に使用されます。この場合は、XMLRefノード型指定されたアトミック値を戻します。