この章では、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式」を参照してください。