この章では、Oracle XML DBでのXQuery言語の使用方法を説明します。XQuery言語でのOracle XML DBサポート、たとえばSQL関数XMLQueryおよびXMLTable、それにSQL*Plus XQUERYコマンドについて説明します。
この章の内容は次のとおりです。
Oracle XML DBのXQuery言語サポートは、SQL/XML関数XMLQueryおよびXMLTableのネイティブ実装により提供されています。便宜性の観点から、SQL*PlusのコマンドXQUERYも用意されており、XQuery式を直接入力することができます。このコマンドにより、SQL*PlusはXQueryコマンドライン・インタプリタになります。
Oracle XML DBは、SQL関数XMLQuery、XMLTable、XMLExistsおよびXMLCastに引数として渡されるXQuery式をコンパイルします。このコンパイルにより、SQL問合せブロックと、SQL/XML関数とXPath関数を使用する演算子ツリーが作成されます。XMLQuery、XMLTable、XMLExistsまたはXMLCastを含むSQL文は一括してコンパイルおよび最適化され、リレーショナル・データベースとXQuery特有の最適化テクノロジの両方を活用します。使用するXML記憶域と索引付けメソッドにより、XPath関数をさらに最適化することができます。結果として生じる最適化された演算子ツリーは、ストリーム方式で実行されます。
|
関連項目:
|
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式では大/小文字が区別されます。式には次のものが含まれます。
1次式: リテラル、変数、または関数アプリケーション。変数名は、たとえば$fooのように、ドル記号($)で始まります。リテラルには、数値、数値、文字、または実体参照。
XPath式: 任意のXPath式。開発中のXPath 2.0標準はXQueryのサブセットになります。XPath 1.0は現在サブセットです。ただしXQueryはリッチな型体系を使用します。
FLWOR式: 最も重要なXQuery式で、次の要素を順番に並べたもので構成されています。FLWORという名もそれに由来しています。for、let、where、order by、return。
XQueryシーケンス: カンマ(,)コンストラクタはシーケンスを作成します。unionやintersectといったシーケンス操作関数も使用できます。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式が各部分式(something、somethingElse、expression1、および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:integer、xs:string。脚注2
型表現は、次のような出現インジケータを持てます。?(オプション。0回または1回)、*(0回以上)、+(1回以上)。たとえば、document-node(element())*、item()+、attribute()?。
XQueryには、型と組み合せて使用する演算子もあります。cast as、castable as、treat as、instance の、typeswitch、およびvalidateなどです。たとえば、"42" cast as xs:integerは、値が整数の2である式です。(厳密には、値が型を表現していないので、これは型表現ではありません。)
XQuery一般について考えた場合、FLWOR式には多くの学習事項があります。この項の説明は簡単な概要にすぎません。
FLWORはXQueryで最も一般的な式構文です。FLWOR(「フラワー」と読みます)は、for、let、where、order by、およびreturnを表しています。FLWOR式には1つ以上のforまたはlet句と、1つのreturn句を持ちます。1つのwhereおよびorder by句がオプションです。
for: 1つ以上の変数を任意の値に順にバインドします。つまり、各変数に対し反復を行いますが、変数を各回の反復で別の値にバインドします。
各回の反復で、変数は出現する順にバインドされ、forリストで$laterの前にリストされた変数$earlierの値が、変数$laterのバインドで使用されます。たとえば、次の式は、2回目の反復で$iを4にバインドし、$jを6(2+4)にバインドします。
for $i in (3, 4), $j in ($i, 2+$i)
let: 1つ以上の変数をバインドします。
forと同様、letでも、letのバインディング・リストで先にリストされている別の変数を使用して(またはforやletで囲むことにより)、変数を計算した値にバインドできます。たとえば、次の式は$jを5(3+2)にバインドします。
let $i := 3, $j := $i + 2
where: forおよびletの変数バインディングを特定の条件に応じてフィルタします。SQLのWHERE句に類似しています。
order by: whereフィルタリングの結果をソートします。
return: 順序付けとフィルタリングがされた値を構成します。これがFLWOR式の最終的な結果です。フラット化されたシーケンスになります。
式forおよびletの機能はFROM句に類似しています。whereの動作はSQLのWHERE句に似ています。order byはSQLのORDER BYに、returnはSQLのSELECTに似ています。両方の言語で名前が共通している2つのキーワード(where、order by)を除いて、FLWOR句の順序はSQL句の順序と反対ですが、対応する句の意味は非常に類似しています。
FLWOR式(order byを含む)の使用は、文書の順序と異なる順序でシーケンスを構成する唯一の方法です。
SQL関数XMLQueryおよびXMLTableは、SQL/XML標準により、SQL言語とXQuery言語の一般インタフェースとして定義されています。他のSQL/XML関数と同様、XMLQueryおよびXMLTableを使用すると、SQLとXML、両方の強力な機能と柔軟性を利用できます。これらの関数を使用すると、リレーショナル・データを使用したXMLデータの構成、XML同様のリレーショナル・データに対する問合せ、およびXMLデータからのリレーショナル・データの構成が可能です。
XMLQueryとXMLTableの両方がXQuery式を評価します。XQuery言語では、式は常に項目のシーケンスを戻します。関数XMLQueryはこのシーケンスの項目を集計し、単一のXML文書または断片を戻します。関数XMLTableは、XQueryシーケンスからの1つの項目を各行に含むSQL表を戻します。
SQL/XML標準は、ISO/IEC 9075-14:2006(E)『Information technology - Database languages - SQL - Part 14: XML-Related Specifications (SQL/XML)』です。これもSQL標準の一部なので、SQL:2003との間で調整されています。この開発を支援している標準化団体は、次の2団体です。
ISO/IEC JTC1/SC32(International Organization for StandardizationおよびInternational Electrotechnical Committee Joint Technical Committee 1, Information technology, Subcommittee 32, Data ManagementおよびInterchange)
INCITS Technical Committee H2(INCITSはInternational Committee for Information Technology Standardsの略)。INCITSは、ANSI(米国規格協会)の方針と手続きに基づいて開発作業を行う公認の標準開発組織です。Committee H2は、SQLとSQL/MMを担当する委員会です。
このSQL/XML標準化プロセスは進行中です。XMLQueryおよびXMLTableの最新情報についてはhttp://www.sqlx.orgを参照してください。
|
関連項目:
|
SQL関数XMLQueryを使用して、XMLデータの構成や問合せができます。この関数は引数としてXQuery式、文字列としてリテラル、そしてオプションで、XQueryコンテキスト項目をSQL式として取ります。コンテキスト項目は、XQuery式を評価する際のXPathコンテキストを確立します。この他に、XMLQueryは、XQuery式の評価の際にXQuery変数にバインドされた値を持つ任意の数のSQL式を引数として受け取ります。関数はXQuery式の評価結果をXMLTypeインスタンスとして戻します。
XML_passing_clause::=

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のコンテキスト項目引数として渡すことができます。例として、例18-8を参照してください。リレーショナル表またはビューをXML同様に問い合せる際に、さらにSQL/XMLビューまで作成せずに済ませるには、XQuery関数ora:viewをXQuery式の内部で使用します。例として、例18-6を参照してください。
|
関連項目:
|
SQL関数XMLTableは、XQuery式の評価結果を新規の仮想表に対するリレーショナル行と列に分解します。その仮想表は、既存のデータベース表に挿入したり、SQLを使用して(join式など)問い合せたりできます(例18-9を参照)。SQLのFROM句でXMLTableを使用します。
XML_namespaces_clause::=

XMLTABLE_options::=

XML_passing_clause::=

XML_table_column::=

XQuery_stringは完結したXQuery式で、プロローグをリテラル文字列として含む場合があります。式の値はXMLTable関数への入力となります。つまり、このXQueryの結果が分解されリレーショナル・データとして格納されます。
オプションのXMLNAMESPACES句にはXML名前空間宣言が含まれており、XML_table_columnのPATH句で、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列を除いて、結果の各columnのdatatypeを指定する必要があります。ただし、次の項目も参照してください。
XMLTableがXML Schemaに基づくXMLType記憶域で使用されている場合、datatypeはオプションとなります。存在しない場合、データ型はXML Schemaから推定されます。Oracle XML DBで、ノードの正しいタイプが特定できない場合は、デフォルトのタイプVARCHAR2(4000)が使用されます。
これはOracleの拡張機能であり、SQL/XML標準では常にdatatypeが必要とされています。
|
注意: 推定されるデータ型は、Oracle XML DBのアップグレードやパッチの適用によって変更される場合があります。特に、以前のリリースではデータ型を特定できなかった(したがってデフォルトのVARCHAR2(4000)が使用された)のに対して、新規リリースやパッチ・セットではデータ型が特定できるようになる場合があります。こうした突然の変更による不具合を発生させないために、datatypeを使用してデータ型を明示的に指定してください。 |
オプションのPATH句は、XQuery式stringにより扱われたXQueryの結果の一部がcolumnコンテンツの一部として使用されることを示しています。複数のPATH句を使用してXQueryの結果を異なる仮想表の列に分割できます。
PATHを省略した場合は、XQuery式がcolumnであるものと仮定されます。たとえば、次の2つの式は等価です。
XMLTable(... COLUMNS foo) XMLTable(... COLUMNS foo PATH 'FOO')
オプションのDEFAULT句は、PATH式の結果が空のシーケンス(またはNULL)になる場合に使用する値を指定します。そのexprは、評価されてデフォルト値を生成するXQuery式です。
|
関連項目:
|
|
注意: Oracle Database 10gリリース2より前のリリースでは、一部の処理の実行にSQL関数tableでXMLSequenceが使用されていました。これらの処理は現在、標準関数XMLTableを使用してより効率的に実行できるようになっています。例については、第3章「Oracle XML DBの使用」を参照してください。 |
SQL/XML生成関数またはXSLTを使用して実行される処理には、XQueryを使用して実行できるものが多く、両者の用途は多くの点で一致しています。あるタスクを実行する際にどのツールを使用するかは、様々な考慮事項に基づいて決定されるものであり、その考慮事項の多くはOracle Database以外に関連するものです。このような一般的な問題については、外部のドキュメントを参照してください。
一般的には、XMLデータに主眼を置いている場合はXQueryが使用され、リレーショナル・データに主眼を置いている場合はSQL/XML生成関数(XMLElement、XMLAggなど)が使用されます。
他の条件が同じであれば、既存のXML文書から抽出されたフラグメントに基づいて問合せによってXML文書を構成する場合は通常、リレーショナル・データからスカラー値を抽出し、SQL/XML生成関数を使用して目的のXMLデータを構成するよりも、通常はXQueryのFLOWR式が単純になります(そのためコードのメンテナンスも簡単になります)。一方、既存のリレーショナル・データに基づいて問合せによってXML文書を構成する場合は、通常、SQL/XML生成関数を使用する方が適しています。
Oracle XML DBに関しては、SQL/XML生成関数を使用しても、XMLQueryおよびXMLTableを使用しても、期待できるパフォーマンスは、同じ一般的なレベルです。これは、いずれも最適化のリライト対象になります。
次の名前空間と接頭辞は、Oracle XML DBでXQueryとともに使用するように事前定義されています。
表18-1 事前定義の名前空間と接頭辞
| 接頭辞 | 名前空間 | 説明 |
|---|---|---|
|
|
|
Oracle XML DB名前空間 |
|
|
|
XPathのローカル関数宣言名前空間 |
|
|
|
XPath関数名前空間 |
|
|
|
XML名前空間 |
|
|
|
XML Schema名前空間 |
|
|
|
XML Schemaインスタンス名前空間 |
これらの接頭辞は、あらかじめXQuery式プロローグで宣言しなくてもXQuery式で使用できます。xml以外は、いずれもプロローグで再定義できます。ora以外の接頭辞はすべて、XQuery標準で事前定義されています。
Oracle XML DBには、W3C標準に用意されているものの他に、いくつかのXQuery関数が追加されています。それらの追加関数はOracle XML DB名前空間、http://xmlns.oracle.com/xdbにあります。この名前空間は事前定義の接頭辞 oraを使用します。この項ではこれらのOracle拡張関数を説明します。
構文
ora:contains (input_text, text_query [, policy_name] [, policy_owner])
XPath関数ora:containsは、XQuery式内のXPath式や、SQL関数existsNode、extract、extractValueなどのコールで使用できます。この関数は、全文述語を使用する構造検索を限定する場合に使用されます。関数ora:containsは、input_textがtext_queryと一致した場合は正の整数を戻します(数字が大きいほど、一致の関連性は高くなります)。一致しない場合は0(ゼロ)を戻します。XQuery式内部で使用される場合、XQueryの戻り型はxs:integer()です。XQuery式外部のXPath式で使用される場合、XPathの戻り型はnumberです。
引数input_textは単一のテキスト・ノードまたは属性に対して評価される必要があります。ora:containsにおけるtext_queryの構文と意味論は、いくつかの制限を伴う他はcontainsにおけるtext_queryと同一です。
構文
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_string – xs:string?脚注3
match_pattern - xs:string
match_parameter - xs:string
|
関連項目: SQL条件REGEXP_LIKEの詳細は、『Oracle Database SQL言語リファレンス』を参照してください。 |
構文
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:matchesの動作はSQL関数regexp_replaceと同じですが、引数の型はSQLデータ型ではなくXQuery型です。引数の型は次のとおりです。
target_string – xs: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 (number)
XQuery関数ora:sqrtは、数値引数の平方根を戻します。引数はXQuery type xs:decimal、 xs:float、またはxs:doubleのいずれかです。戻り値のXQuery型は引数と同じです。
構文
ora:view ([db-schema STRING,] db-table STRING) RETURNS document-node(element())*脚注5
XQuery関数ora:viewを使用すると、XQuery表現の内部にある既存のデータベース表やビューを、XML文書と同様に問い合せることができます。実際には、ora:viewはリレーショナル・データのXMLビューをその場で作成します。このため、ora:viewを使用して、リレーショナル・データの他にXMLビューを明示的に作成しないようにすることができます。
入力パラメータは次のとおりです。
db-schema: データベース・スキーマの名前を示すオプション文字列リテラル
db-table: データベースの表またはビューの名前を示す文字列リテラルdb-schemaが存在する場合、db-tableはデータベース・スキーマdb-schema内にあります。
関数ora:viewは、db-tableの各行に1つずつ、documentノードの順序のないシーケンスを戻します。SQL/XML標準は、各入力行を出力XML文書にマップします。リレーショナル列名がXML要素名になります。db-tableの型がXMLTypeの場合を除き、指定されたテーブル行から導出された列要素がROW要素内に囲まれます。その場合、戻り値の型は、正確にはdocument-node(element(ROW))*となります。
XQueryは非常に汎用性と表現力に富む言語で、SQL関数XMLQuery、XMLTableおよびXMLExistsにより、それらの表現力と計算力がSQLの同様の長所と組み合されます。この項では、これら2つのSQL/XML関数でできることについて説明します。XMLExistsの詳細は、「XMLEXISTS SQL Function」を参照してください。
Oracle XML DBでは、通常は次のようにXQueryを使用します。ここでの例は、それらの使用方法の違いを示すように構成されています。
Oracle XML DBリポジトリ内でXMLデータを問い合せる。
リレーショナル表またはビューを、XMLデータと同様に問い合せる。Oracle XQuery関数ora:viewを使用して、リレーショナル・データのXMLビューをその場で作成します。
「ora:viewを使用したXQuery式内でのリレーショナル・データ問合せ」を参照してください。
XMLTypeリレーショナル・データを問い合せ、場合により関数XMLTableを使用して結果のXMLをリレーショナル・データに分解します。
「XQueryのXMLTypeデータとの使用」を参照してください。
例18-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://emp.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が汎用のシーケンス操作言語であるということです。式や結果は、XMLデータでなくてもかまいません。XQueryシーケンスは数値、文字列、ブール値、日付など任意のXQuery型の項目と、様々な型のXMLノード(document-node()、element()、attribute()、text()、namespace()など)を含むことができます。例18-2に例を示します。
例18-2 様々な型の項目シーケンスに適用されるXMLQuery
この例では、SQL関数XMLQueryを、異なる様々な種類の項目を含むXQueryシーケンスに適用します。
整数リテラル: 1
算術式: 2 + 3
文字列リテラル: "a"
整数のシーケンス: 100 to 102
構成されたXML要素ノード: <A>33</A>
次の例は、カンマ演算子(,)とカッコ((、))を使用してグループ化したシーケンスの構成を示しています。
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.
シーケンス式100 to 102の評価結果はシーケンス(100, 101, 102)なので、XMLQueryの引数は、ネストされたシーケンスを含むシーケンスです。シーケンス引数は、XQueryシーケンスと同様、自動的にフラット化されます。実際の引数は、(1, 5, "a", 100, 101, 102, <A>33</A>)となります。
この項では、XQueryとXMLデータをOracle XML DBリポジトリとともに使用する例を紹介します。Oracle XML DBでは、関数fn:docおよびfn:collectionはリポジトリ内のファイルやフォルダ・リソースをそれぞれ戻します。この項のそれぞれの例では、XQuery関数fn:docを使用してXMLデータを含むリポジトリ・ファイルを取得し、FLWOR式の句forおよびletを使用してXQuery変数をそのデータの部分にバインドしています。
例18-3 For、Let、Order By、Where、およびReturnを使用するFLOWR式
この例は、Oracle XML DBリポジトリ内の2つのXML文書リソース、/public/emps.xmlおよび/public/depts.xmlを問い合せます。可能なそれぞれのFLWOR式の句の用法が、fn:docの用法とともに説明されています。
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.
例18-3では、各種のFLWOR句が次の操作を行っています。
forは/public/emps.xml内のemp要素について反復を実行し、変数$eを各要素の値に順にバインドします。つまり、従業員全体のリストについて反復を実行し、$eを各従業員にバインドします。
letは変数$dを、/public/emps.xml内の、deptno属性が要素$eのdeptno属性と同じであるdept要素が持つdname属性のすべての値で構成されているシーケンスにバインドします。(結合操作)。つまり、これは$dを、従業員$eの部門と同じ部門番号を持つすべての部門の名前にバインドします。(depts.xml内の各deptno値に対してdname値が一意であることもあり得ます。)forと異なりletは値に対して反復を行わないことに注意してください。この例で、$dは1度だけバインドされています。
forとletを同時に使用すると、タプル($e, $d)のストリームを生成できます。ここで$eはある従業員、$dはその従業員が所属するすべての部門の名前(この場合は従業員の一意の部門の一意の名前)を表します。
whereはそのタプル・ストリームをフィルタリングし、給与が100,000を超える従業員のみを残します。
order byは、フィルタリングされたタプル・ストリームを従業員番号empnoでソートします(デフォルトでは昇順)。
returnは、各タプルについて1つのemp要素を構成します。それらの要素の属性enameおよびdeptが、それぞれ入力の属性enameおよび$dを使用して構成されます。出力内の要素名と属性名empおよびenameと入力文書emps.xml内の同じ名前の間に必然的な関係はないことに注意してください。
例18-4でもFLWOR式の句をそれぞれ使用しています。さらに、fn:doc以外のXQuery関数の使用方法も示しています。
例18-4 組込み関数を使用したFLOWR式
この例は、組込みXQuery関数http://www.w3.org/2003/11/xpath-functionsの名前空間にあるXQuery関数doc、count、avg、およびintegerの使用方法を示しています。 This namespace is bound to the prefix fn.
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.
例18-4では、各種のFLWOR句が次の操作を行っています。
forは、入力文書/public/depts.xml内のdeptno属性について反復を実行し、変数$dを各属性の値に順にバインドします。
letは変数$eを、入力文書/public/emps.xmlの、deptno属性が$dという値を持つすべてのemp要素で構成されるシーケンスにバインドします(join操作)。
Together, forとletを同時に使用すると、タプル($d, $e)のストリームを生成できます。ここで$dは部門番号、$eはその部門の従業員の集合を表します。
whereはそのタプル・ストリームをフィルタリングし、1人以上の従業員を持つタプルのみを残します。
order byは、フィルタリングされたタプル・ストリームを平均給与の降順でソートします。平均は、名前空間fnのXQuery関数avgを、属性salaryの値に適用して計算します。この値は$eのemp要素に連結されています。
returnは、order byで生成された各タプルについて1つのbig-dept要素を構成します。big-deptのtext()ノードには、$dにバインドされた部門番号が含まれます。XQuery関数countで指定されたとおり、headcount子要素には、従業員数が$eにバインドされて含まれます。avgsal子要素には、計算された平均給与が含まれます。
この項では、Oracle XQuery関数ora:viewを使用して、XMLデータ同様の方法でXQuery式の内部からリレーショナル・データを問い合せる例を紹介します。
例18-5 ora:viewを使用してリレーショナル表をXMLビューとして問い合せる
この例ではOracle XQuery関数ora:viewをFLWOR式で使用して、2つのリレーショナル表regionsおよびcountriesの結合を問い合せています。どちらの表も、サンプル・データベース・スキーマhrに属しています。この例ではさらに、SQLスカラー値AsiaがXQuery変数$regionnameに渡されています。どのSQL式でも、評価することによってPASSINGを使用してXQueryに渡す値を生成できます。その場合、値はSQL*Plus変数REGIONにより与えられます。またこの値は、適切なスカラーSQLデータ型(この場合はVARCHAR2(40))にキャストする必要があります。
DEFINE REGION = 'Asia'
SELECT XMLQuery('for $i in ora:view("REGIONS"), $j in ora:view("COUNTRIES")
where $i/ROW/REGION_ID = $j/ROW/REGION_ID
and $i/ROW/REGION_NAME = $regionname
return $j'
PASSING CAST('®ION' 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.
例18-5では、各種のFLWOR句が次の操作を行っています。
forは、ora:viewのコールにより戻されるXML要素のシーケンスについて反復を実行します。最初のコールでは、各要素はリレーショナル表regionsの行に対応し、変数$iにバインドされます。同様に、ora:viewの2回目のコールでは、$jは、表countriesの後続する行にバインドされます。regionsおよびcountriesはXMLType表ではないため、各表の行に対応する最上位要素はROWです(ラッパー要素)。行要素についての反復は順序付けられていません。
whereは両方の表から行をフィルタリングし、各表でregion_idが同一であり(region_idに結合を実行)、region_nameがAsiaである行のペアのみを残します。
returnは、countries表からの行を、ROWを最上位要素とする、XMLフラグメントを含むXML文書として戻します。
例18-6では、ネストされたFLWOR式でora:view を使用しています。
例18-6 ネストされたFLWOR問合せでのora:viewの使用
この問合せは、ネストされたFLWOR式の使用例です。アクセスするリレーショナル表は、サンプル・データベース・スキーマoeにあるwarehousesと、サンプル・データベース・スキーマhrにあるlocationsです。この例をユーザーoeとして実行するには、最初にユーザーhrとして接続し、ユーザーoeに対して、表locationsでSELECT操作を実行する権限を付与する必要があります。ここでは、2つの引数を持つ形式のora:viewが使用されており、表(最初の引数)の他にデータベース・スキーマ(2番目の引数)を指定しています。
CONNECT hr Enter password: password Connected. GRANT SELECT ON LOCATIONS TO OE / CONNECT oe Enter password: password Connected. SELECT XMLQuery( 'for $i in ora:view("OE", "WAREHOUSES")/ROW return <Warehouse id="{$i/WAREHOUSE_ID}"> <Location> {for $j in ora:view("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;
これによって、次の結果が戻されます。(ここではわかりやすいように、この結果をフォーマット出力しています。)
XMLQUERY('FOR$IINORA:VIEW("OE","WAREHOUSES")/ROWRETURN<WAREHOUSEID="{$I/WAREHOUS
--------------------------------------------------------------------------------
<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.
例18-6では、各種のFLWOR句が次の操作を行っています。
外側のforはora:viewにより戻されたXML要素のシーケンスについて反復を実行します。各要素はリレーショナル表warehousesの行に対応していて、変数$iにバインドされています。warehousesはXMLType表ではないので、行に対応する最上位の要素はROWとなります。行要素についての反復は順序付けられていません。
内側のforも同様にora:viewにより戻されたXML要素のシーケンスについて反復を実行します。各要素はリレーショナル表locationsの行に対応していて、変数$jにバインドされています。
whereはタプル($i, $j)をフィルタリングし、location_id の子が、$iおよび$jに対して同じであるタプルだけを残します(location_idに基づいてjoinを実行します)。
内側のreturnは、要素 STREET_ADDRESS、CITY、およびSTATE_PROVINCEのXQueryシーケンスを、すべてlocations表のROW要素 $jの子、つまり、locations表の同名の列の値として構成します。
外側のreturnは内側のreturnの結果をLocation要素で囲み、それをさらにWarehouse要素で囲みます。Warehouse要素に対して、値を表warehousesのwarehouse_id列から取得したid属性を提供します。
例18-7 XMLTableでora:viewを使用してリレーショナル表をXMLとして問い合せる
この例では、SQL関数XMLTableは、XQuery問合せの結果を仮想リレーショナル・データに分解するために使用されています。この例で使用されているXQuery式は例18-6で使用されているものと同一です。XQuery式の評価結果はWarehouse要素のシーケンスです。関数XMLTableは、行がWarehouse要素である仮想リレーショナル表を生成します。正確には、仮想表の各行に対応する疑似列COLUMN_VALUEはXMLフラグメント(XMLType型)で、単一のWarehouse要素を持ちます。
SELECT *
FROM XMLTable(
'for $i in ora:view("OE", "WAREHOUSES")/ROW
return <Warehouse id="{$i/WAREHOUSE_ID}">
<Location>
{for $j in ora:view("HR", "LOCATIONS")/ROW
where $j/LOCATION_ID eq $i/LOCATION_ID
return ($j/STREET_ADDRESS, $j/CITY, $j/STATE_PROVINCE)}
</Location>
</Warehouse>');
これにより例18-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.
この項では、XQueryをXMLTypeリレーショナル・データとともに使用する例を紹介します。
例18-8 XMLQueryでPASSING句を使用してXMLType列を問い合せる
この例では関数XMLQueryでPASSING句を使用して、XMLType列oe.warehouse_specをコンテキスト項目としてXQueryに渡します。これにより、領域が80,000を超えるウェアハウス(/Warehouse/ Area > 80000)のそれぞれについてDetails要素が作成されます。
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 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.
例18-8では、関数XMLQueryは表warehousesの各行のwarehouse_spec列に適用されます。各FLWOR句は次の操作を実行します。
forは列warehouse_spec(渡されたコンテキスト項目)の各行のWarehouse要素について反復を実行します。各要素はそれぞれ$iにバインドされます。反復は順序付けられていません。
whereはWarehouse要素をフィルタリングして、Area子の値が80,000を超えるもののみを残します。
returnはDetailsの要素のXQueryシーケンスを構成します。各要素は子要素DocksおよびRailを含みます。構成されたDocks要素のnum属性はWarehouseの子Docksのtext()値に設定されます。Railのtext()コンテンツは、要素WarehouseのRailAccess属性の値に応じて、trueまたはfalseに設定されます。
SELECT文は表warehousesの各行に適用されます。XMLQuery式は、XQuery式に一致しない行については空のシーケンスを戻します。New JerseyとSeattleの倉庫のみがXQuery問合せに適合するので、それらの倉庫についてのみ<Details>...</Details>が戻されます。
例18-9 XMLTableでXML Schemaに基づくデータを使用する
この例はSQL関数XMLTableを使用して、XML Schemaベースのデータを含むXMLType表hr.purchaseorderを問い合せます。PASSING句を使用して、XMLTableのXQuery式の引数のコンテキスト項目としてpurchaseorder表を提供します。結果として得られる仮想表の疑似列COLUMN_VALUEは、CostCenter要素が値A10を持ち、User要素が値SMCCAINを持つReference情報を含む、構成された要素A10poを保持します。この問合せは、仮想表とデータベース表purchaseorderの間の結合を実行します。
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.
関数XMLTableのPASSING句により、XMLTypeのOBJECT_VALUEがpurchaseorder表に渡され、XPathコンテキストとして使用されます。つまり、XMLTable式はpurchaseorder表に依存します。このため、表purchaseorderは、FROMリストのXMLTable式よりも前に記述する必要があります。これは、データの依存関係が存在する状況では一般的な要件です。
例18-10 XMLQueryでXML Schemaに基づくデータを使用する
この例で得られる結果は例18-9に類似しています。XMLTableのかわりにXMLQueryを使用してhr.purchaseorderを問い合せます。次の2つの例では、XQuery式により戻される空のシーケンスの処理が異なります。例18-9では、これらの空のシーケンスはpurchaseorder表を使用して結合されないため、SQL問合せの結果セットは全体で10行のみとなります。例18-10では、これらの空のシーケンスは、132行が含まれ、それぞれが表purchaseorderの各行に対応するSQL問合せの結果セットの一部となります。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;
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.
例18-11 XMLTableでのPASSINGおよびCOLUMNS句の使用
この例では、XMLTable句PASSINGおよびCOLUMNSを使用します。XQuery式は最上位のPurchaseOrder要素について反復を実行し、コスト・センターA10を含む発注書に対応するPO要素を構成します。結果のPO要素は続いてXMLTableに渡されて処理されます。
PurchaseOrderの子から取得したデータは、POの子、Ref、Type、およびNameを構成するのに使用されます。Typeのコンテンツは/PurchaseOrder/SpecialInstructionsのコンテンツから取得されますが、SpecialInstructionsのクラスはTypeに対応して異なる方法で分割されます。
関数XMLTableはXQuery評価の結果を、poref、priority、およびcontactの仮想表の3つのVARCHAR2列に分割します。DEFAULT句は、Regularのデフォルトのpriorityを指定するのに使用されます。
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.
例18-12 XMLTableを使用してXMLコレクション要素をリレーショナル・データに分解する
この例では、SQL関数XMLTableは、XMLTypeコレクション要素LineItemの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 declare namespace宣言をXQuery式のプロローグで使用して、名前空間の接頭辞を定義することができます。declare default namespaceを使用して、式のデフォルトの名前空間として名前空間を確立できます。
名前空間宣言を記述した行の末尾にセミコロン(;)を置いた場合、SQL*Plusでは、そのセミコロンがSQLの終端文字として解釈されます。SQL*Plusを使用する場合は、この点に注意が必要です。これを避けるには、次のいずれかを実行します。
同じ行のセミコロンの後にテキストを挿入する。
同じ行のセミコロンの後に、(: :)のようなコメントを挿入する。
SQL*PlusコマンドSET SQLTERMINATORを使用して、SQLの終端文字の認識を無効にする。
例18-13 XMLQueryでの名前空間宣言の使用
SELECT XMLQuery('declare namespace e = "http://emp.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://emp.com"; for
$i in doc("/public/empsns.xml")/e:emps/e:emp
let $d :=
doc("/public/depts.xml")//dept[deptno=$i/@e:deptno]/@dname
where $i/@e:salary > 100000
order by $i/@e:empno
return <emp ename="{$i/@e:ename}" dept="{$d}"/>'
RETURNING CONTENT) FROM DUAL;
XMLQUERY('DECLARENAMESPACEE="HTTP://EMP.COM";FOR$IINDOC("/PUBLIC/EMPSNS.XML")/E:
--------------------------------------------------------------------------------
<emp ename="Jack" dept=""></emp><emp ename="Jill" dept=""></emp>
-- This works too - add a comment after the ";".
SELECT XMLQuery('declare namespace e = "http://emp.com"; (: :)
for $i in doc("/public/empsns.xml")/e:emps/e:emp
let $d := doc("/public/depts.xml")//dept[deptno=$i/@e:deptno]/@dname
where $i/@e:salary > 100000
order by $i/@e:empno
return <emp ename="{$i/@e:ename}" dept="{$d}"/>'
RETURNING CONTENT) FROM DUAL;
XMLQUERY('DECLARENAMESPACEE="HTTP://EMP.COM";(::)FOR$IINDOC("/PUBLIC/EMPSNS.XML"
--------------------------------------------------------------------------------
<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://emp.com";
for $i in doc("/public/empsns.xml")/e:emps/e:emp
let $d :=
doc("/public/depts.xml")//dept[deptno=$i/@e:deptno]/@dname
where $i/@e:salary > 100000
order by $i/@e:empno
return <emp ename="{$i/@e:ename}" dept="{$d}"/>'
RETURNING CONTENT) FROM DUAL
/
XMLQUERY('DECLARENAMESPACEE="HTTP://EMP.COM";FOR$IINDOC("/PUBLIC/EMPSNS.XML")/E:
--------------------------------------------------------------------------------
<emp ename="Jack" dept=""></emp><emp ename="Jill" dept=""></emp>
XQuery名前空間宣言は、XQuery式の外部では無効です。XMLTable式で使用する名前空間接頭辞をXQuery式の外部で宣言するにはXMLNAMESPACES句を使用します。この句はXMLTableのXQuery式の引数でも使用できるため、XQueryプロローグを別個に宣言する必要はありません。
例18-14では、XMLNAMESPACESは名前空間http://emp.comに対応する接頭辞eを定義するために使用されます。この名前空間はCOLUMNS句とXMLTable式のXQuery式で使用されます。
例18-14 XMLTableでのXMLNAMESPACES句の使用
SELECT * FROM XMLTable(XMLNAMESPACES('http://emp.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:empnoがCOLUMNS句に存在することにより、XMLNAMESPACES句を使用する必要が生じています。そうでなければ、XQuery式だけのためにはプロローグ名前空間宣言(declare namespace e = "http://emp.com")で十分です。
XMLTable式で同一の名前空間が使用されているので、デフォルトの名前空間XMLNAMESPACES (DEFAULT 'http://emp.com')を使用できます。このため、修飾名$i/e:emps/e:empを、明示的接頭辞を使用せずに$i/emps/empと書いてかまいません。
前述のように、Oracle XML DBでは一般に、同等のリレーショナル式を評価することによりXQuery式を評価します。この最適化ではXPathのリライトと同じメカニズムが使用され、同じ利点をもたらします。問合せのチューニングは、SQLのパフォーマンスと同様に、XQueryのパフォーマンスも改善することができます。XQueryのパフォーマンスをチューニングするには、該当するXML記憶域モデルと索引を選択します。
一般のデータベースの問合せと同様に、チューニングが必要かどうかは、問合せのEXPLAIN PLANをチェックして決定します。計画が最適でない場合は、次のマニュアルで個別のチューニング情報を参照してください。
構造化記憶域: 「XPathリライトの理解および最適化」および第7章「XPathリライト」
非構造化記憶域およびバイナリXML記憶域: 第5章「XMLTypeデータの索引付け」
また、次のXQuery式は処理コストがかかることがあり、そのため、大量のデータを処理する場合にパフォーマンスにオーバーヘッドが発生する可能性があることに注意してください。
リバース軸(ancestor、ancestor-or-self、parent、precedingおよびpreceding-siblingの各軸)
XQuery関数fn:positionおよび位置指定述語(たとえば[1])
この項では、この章でこれまでに示した例の一部について、EXPLAIN PLANの実行の実際を説明します。XQuery式のターゲットに応じて、例は次のグループに分けて示します。
ora:viewを使用してその場で作成されるSQL/XMLビュー
オブジェクト・リレーショナル形式で格納されているXML Schemaに基づくXMLType表
非構造化記憶域またはバイナリXML記憶域でXMLTypeデータを問い合せる場合にXQuery式のパフォーマンスをさらに改善するためには、XMLIndexを使用できます。
例18-15に、ora:viewにより作成されたSQL/XMLビューに関するXMLQueryの最適化を示します。例18-16に、同じコンテキストにおけるXMLTableの最適化を示します。
例18-15 ora:viewを含むXMLQueryの最適化
例18-6をもう一度見てみます。
SELECT XMLQuery(
'for $i in ora:view("OE", "WAREHOUSES")/ROW
return <Warehouse id="{$i/WAREHOUSE_ID}">
<Location>
{for $j in ora:view("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;
この例のEXPLAIN PLANは、問合せが最適化されていることを示しています。
PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------- Plan hash value: 2976528487 -------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | | 2 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 41 | | | | 2 | NESTED LOOPS | | 1 | 41 | 3 (0)| 00:00:01 | | 3 | TABLE ACCESS BY INDEX ROWID| LOCATIONS | 1 | 41 | 1 (0)| 00:00:01 | |* 4 | INDEX UNIQUE SCAN | LOC_ID_PK | 1 | | 0 (0)| 00:00:01 | | 5 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 6 | SORT AGGREGATE | | 1 | 185 | | | | 7 | NESTED LOOPS | | 9 | 1665 | 4 (0)| 00:00:01 | | 8 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 9 | TABLE ACCESS FULL | WAREHOUSES | 9 | 1665 | 2 (0)| 00:00:01 | | 10 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | -------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("LOCATION_ID"=:B1) 22 rows selected.
例18-16 ora:viewを含むXMLTableの最適化
例18-7をもう一度見てみます。
SELECT *
FROM XMLTable(
'for $i in ora:view("OE", "WAREHOUSES")/ROW
return <Warehouse id="{$i/WAREHOUSE_ID}">
<Location>
{for $j in ora:view("HR", "LOCATIONS")/ROW
where $j/LOCATION_ID eq $i/LOCATION_ID
return ($j/STREET_ADDRESS, $j/CITY, $j/STATE_PROVINCE)}
</Location>
</Warehouse>');
この例のEXPLAIN PLANは、問合せが最適化されていることを示しています。
PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------- Plan hash value: 2573750906 -------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 9 | 1665 | 4 (0)| 00:00:01 | | 1 | SORT AGGREGATE | | 1 | 41 | | | | 2 | NESTED LOOPS | | 1 | 41 | 3 (0)| 00:00:01 | | 3 | TABLE ACCESS BY INDEX ROWID| LOCATIONS | 1 | 41 | 1 (0)| 00:00:01 | |* 4 | INDEX UNIQUE SCAN | LOC_ID_PK | 1 | | 0 (0)| 00:00:01 | | 5 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 6 | NESTED LOOPS | | 9 | 1665 | 4 (0)| 00:00:01 | | 7 | FAST DUAL | | 1 | | 2 (0)| 00:00:01 | | 8 | TABLE ACCESS FULL | WAREHOUSES | 9 | 1665 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 4 - access("LOCATION_ID"=:B1) 20 rows selected.
例18-17に、XML Schemaに基づくXMLType表に関するXMLQueryの最適化を示します。例18-18に、同じコンテキストにおけるXMLTableの最適化を示します。
例18-17 XML Schemaに基づくXMLTypeデータを含むXMLQueryの最適化
例18-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;
この例のEXPLAIN PLANは、問合せが最適化されていることを示しています。
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.
例18-18 XML Schemaに基づくXMLTypeデータを含むXMLTableの最適化
例18-12をもう一度見てみます。
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;
この例のEXPLAIN PLANは、問合せが最適化されていることを示しています。XQueryの結果は生成されません。結果セット全体を生成するにはXMLのコレクション要素LineItemの基礎となる記憶域の列が使用されます。
PLAN_TABLE_OUTPUT ---------------------------------------------------------------------------------------- Plan hash value: 3113556559 ---------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | ---------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 4 | 376 | 6 (0)| 00:00:01 | | 1 | NESTED LOOPS | | 4 | 376 | 6 (0)| 00:00:01 | |* 2 | TABLE ACCESS FULL| PURCHASEORDER | 1 | 37 | 5 (0)| 00:00:01 | |* 3 | INDEX RANGE SCAN | SYS_IOT_TOP_48748 | 3 | 171 | 1 (0)| 00:00:01 | ---------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - 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"><re ad-properties/><read-contents/></privilege>'))=1) 3 - access("NESTED_TABLE_ID"="PURCHASEORDER"."SYS_NC0003400035$") filter("SYS_NC00013$">50 AND "SYS_NC00012$">2 AND "ITEMNUMBER">=8) 22 rows selected.
この例では、表hr.purchaseorderの全体が検索され、各発注書に対してXMLTable式が評価されます。しかし、purchaseorder表でなくXMLTable式にSQL問合せの実行をまかせる方が効率的です。つまり、XQuery式はリレーショナル式に書きなおされていますが、基礎となるリレーショナル・データに基づいて索引を作成することによって最適化を改善できます。この問合せは、純粋なSQL問合せを最適化する場合と同じ方法で最適化できます。
これは、Oracle XML DBのXQueryには常にあてはまります。SQLで使用する最適化テクニックをそのまま使用できます。
コレクション要素LineItemのUnitPrice属性は、適切な索引ターゲットです。適用されるXMLスキーマが、Ordered Collection Table(OCT)を使用してLineItem要素を格納することを指定しています。
ただし、このOCTの名前は、XML発注書がXML Schemaに基づくデータとして分解されたときに、Oracle XML DBにより生成されます。サンプル・データベース・スキーマhrの表purchaseorderを使用するかわりに、説明のために、プロパティとデータが同じで、OCTにわかりやすい名前が付いた新しいpurchaseorder表を(異なるデータベース・スキーマに)手動で作成します。手順は例3-11を参照してください。
例3-11と同様にpurchaseorder表が作成されたと仮定すると、次の文を使用して適切な索引を作成できます。
CREATE INDEX unitprice_index ON lineitem_table("PART"."UNITPRICE");
この索引が定義されている場合、例18-12により、XMLTable式が全体の評価を実行することを示すEXPLAIN PLANが結果として得られます。
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.
Oracle XML DBはすべてのXQuery式を型チェックします。しかし、実行時の型チェックはコストがかかることがあります。最適化技法として、指定された問合せに対してコンパイル時に十分な静的型情報を利用できる場合は常に、Oracle XML DBはその問合せの静的な(コンパイル時)型チェックを行います。指定された問合せに対してコンパイル時に十分な静的型情報を利用できない場合は、Oracle XML DBはその問合せの動的(実行時)型チェックを使用します。
静的型チェックでは、コンパイル時にエラーが発生するので、実行時間を節約できることがあります。静的型チェック・エラーには、データ型エラーと、XML Schemaの観点から無効であるXPath式の使用の両方を含みます。
コンパイル時に十分な静的型情報を提供する一般的な方法には、次の方法があります。
XQueryをora:viewとともに使用してリレーショナル・データのXMLビューを問い合せます。
XQueryを使用して、問合せコンパイル時にXML Schema情報を利用できるXMLType表、列またはビューを問い合せます。
この項では、静的型チェックの有効性と、型情報を通信するこれら2つの手段の使用方法を示す例を紹介します。
例18-19 XQuery式の静的型チェック - ora:view
Oracle XQuery関数ora:viewによりその場で生成されるXMLビューの最上位要素はROWですが、この例ではROWラッパー要素が不正に脱落しています。この脱落により、コンパイル時エラーが発生します。このようにora:viewによりリレーショナル・データを囲み忘れる誤りは発生しやすいものですが、静的型チェックを使用しないと診断が困難な場合があります。例18-5に正しいコードを示します。
-- This produces a static-type-check error, because "ROW" is missing.
SELECT XMLQuery('for $i in ora:view("REGIONS"), $j in ora:view("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 ora:view("REGIONS"), $j in ora:view("COUNTRIES")
*
ERROR at line 1:
ORA-19276: XPST0005 - XPath step specifies an invalid element/attribute name:
(REGION_ID)
例18-20 XQuery式の静的型チェック - スキーマベースのXML
この例では、XQueryの静的型チェックにより、XPath式とターゲットXMLのスキーマ・ベースのデータの不一致を検出します。要素CostCenterが、ここではcostcenterと誤ったスペルになっています(XQueryおよびXPathは大文字/小文字を区別します)。例18-11に正しいコードを示します。
-- 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)
例18-21は、XQuery式の前にSQL*PlusコマンドXQUERYを付け、式の後にスラッシュ(/)を単独で付けることにより、SQL*PlusコマンドラインでXQuery式を直接入力する方法を示しています。Oracle Databaseでは、このコマンドで送信されたXQuery式を、SQL関数XMLQueryおよびXMLTable内のXQuery式と同様に処理します。実行は同一で、同じ最適化を使用します。
例18-21 SQL*Plus XQUERYコマンドの使用
SQL> XQUERY for $i in ora:view("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ユーザーズ・ガイドおよびリファレンス』 |
この章の前項で、SQLからXQueryを呼び出す方法を示しました。この項では、XQueryを、PL/SQL、JDBC、およびOracle Data Provider for .NET(ODP.NET)用のOracle APIとともに使用する例を示します。
例18-22 XQueryをPL/SQLとともに使用する
この例は、XQueryをPL/SQLとともに使用する方法、特に、XMLQueryのPASSING句を使用して動的変数をXQuery式にバインドする方法を示します。バインド変数:1および:2は、PL/SQLバインド変数nbitemsおよびpartidに、それぞれバインドされます。その後、それぞれXQuery変数itemnoおよびidとしてXQueryに渡されます。
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 ora:view("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.
例18-23 XQueryをJDBCとともに使用する
この例は、XQueryをJDBCとともに使用して、変数をその位置によってSQL関数XMLTableのPASSING句にバインドします。
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 ora:view(\"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());
}
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
例18-24 XQueryをODP.NETおよびC#とともに使用する
この例は、XQueryをODP.NETおよびC#言語とともに使用する方法を示しています。C#の入力パラメータ:nbitemsおよび:partidは、それぞれXQuery変数itemnoおよびidとしてXQueryに渡されます。
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=ora11gr1"; // 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 ora:view(\"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>
この項では、XQuery言語のためのOracle XML DBについて説明します。
Oracle XML DBのXQuery言語サポートは、リレーショナル記憶域の使用範囲とXMLデータの問合せの使用範囲のベスト・フィットの実現を目指しています。つまり、Oracle XML DBは一般的なXQuery実装ですが、それと同時に、リレーショナル問合せとXML問合せの連携動作に特に注意して設計されています。
この項では、Oracle XML DBのXQuery実装の個別のプロパティについて説明します。XQuery標準は、言語処理の一部の特性について、実装により定義されるのか、実装に依存するのかを明示的にコール・アウトしています。また、XQuery標準で規定されているが、Oracle XML DBでサポートされていない機能もいくつかあります。
XQuery仕様では、言語処理の次の点に関しては実装により定義するように指定されています。
暗黙的タイムゾーン・サポート: Oracle XML DBでは、暗黙的タイムゾーンを常にZと仮定しています。タイムゾーンのないxs:date、xs:timeおよびxs:datetimeのインスタンスは、自動的にUTCに変換されます。
XQuery標準で規定されている次の機能は、Oracle XML DBではサポートされていません。
copy-namespacesモード: Oracle XML DBでcopy-namespaces宣言についてサポートされるのは、preserveとinheritだけです。これは、既存の要素ノードが要素コンストラクタまたは文書コンストラクタによってコピーされた場合、有効範囲内にある元の要素のすべての名前空間がコピーでも維持されることを意味します。それ以外の場合、コピーされたノードは有効範囲内にある構成されたノードのすべての名前空間を継承します。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を使用します。
Oracle XML DBでは、XQuery 1.0およびXPath 2.0の関数および演算子の最新の仕様に含まれるXQueryの関数と演算子がすべてサポートされていますが、次の例外があります。次のものはサポートされていません。
XQueryの正規表現関数(fn:matches、fn:replaceおよびfn:tokenizer)。fn:matchesおよびfn:replaceのかわりにOracle XQuery関数ora:matchesおよびora:replaceを使用します。
関数fn:idおよびfn:idref。
引数のない関数fn:collection。
XQuery関数のオプションの照合パラメータ。
Oracle XML DBでは、Oracle XML DBリポジトリにあるすべてのリソースについて、XQuery関数fn:doc、fn:collectionおよびfn:doc-availableがサポートされています。
関数docはURI引数によりターゲットとされているリポジトリのファイル・リソースを戻します。このリソースは整形式のXMLデータのファイルにしてください。関数collectionも同様ですが、リポジトリのフォルダ・リソースに対して機能します(フォルダ内の各ファイルには整形式のXMLデータが含まれている必要があります)。これらの各関数は、ターゲットとなっているリソースが検出されない場合には空のシーケンスを戻します。エラーは発生しません。関数fn:doc-availableは、そのリソース引数が存在するかどうかをテストします。存在する場合はtrue、しない場合はfalseを戻します。
脚注の凡例
脚注1: 戻り値は、通常と同様、シーケンスです。ただしXQueryでは、項目が1つのシーケンスはその項目自身と等価です。この場合、その単独の項目はブール値です。xsは、XML Schemaの名前空間http://www.w3.org/2001/XMLSchemaであらかじめ定義されています。?)は0回または1回出現することを示すインジケータで、引数が空のシーケンスである場合もあります。「XQuery式」を参照してください。?)は0回または1回出現することを示すインジケータで、引数が空のシーケンスである場合もあります。「XQuery式」を参照してください。*)は0回以上出現することを示すインジケータで、引数が、型要素の文書ノードの空のシーケンスである場合もあります。「XQuery式」を参照してください。