ヘッダーをスキップ
Oracle XML DB開発者ガイド
11gリリース1(11.1)
E05669-02
  目次
目次
索引
索引

戻る
戻る
 
次へ
次へ
 

7 XPathリライト

この章では、Oracle XML DBでのXPathリライトの基礎、およびそれをXML Schemaに基づく構造化記憶域に対して使用する方法について説明します。SQL関数(existsNodeextractextractValueXMLSequenceupdateXMLinsertChildXMlおよびdeleteXML)のXPath式引数のリライトについて詳しく説明します。

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

XPathリライトの概要

オブジェクト・リレーショナル形式(構造化記憶域)で格納されているXML Schemaに基づくデータでは、XQuery式を使用してそのデータを問い合せると、多くの場合、問合せは基礎となるオブジェクト・リレーショナル列に直接リライトされます。このクエリー・リライトは、特定のXML Schemaに基づかないXMLTypeビューでXQuery式を使用して問合せを行った場合も発生します。XQuery式のリライトの最適化プロセスを、XPathリライトといいます。

この最適化によって、Bツリーまたは他の索引が列に存在する場合、これらをオプティマイザによる問合せの評価に使用できます。XPathリライトのメカニズムは、XMLQueryXMLTableXMLExistsexistsNodeextractextractValueupdateXMLなどのSQL関数へのXPath式引数に対して使用されます。これにより、メモリー内でXML文書を構成せずに、XPath式をXML文書に対して評価できます。

Oracle XML DBによってリライトされるXPath式は、Oracle XML DBでサポートされるXPath式の適切なサブセットです。機能性を損なわずにXPath式をリライトできる場合は、リライト可能なXPath式を使用してください。

例7-1 XPathリライト

たとえば、次のような問合せでは、Company要素の値の取得およびリテラル文字列Oracleとの比較が試行されます。

SELECT OBJECT_VALUE FROM mypurchaseorders
  WHERE extractValue(OBJECT_VALUE, '/PurchaseOrder/Company') = 'Oracle';

mypurchaseordersがXML Schemaに基づく構造化記憶域で作成されているとすると、extractValue式は、発注書についての企業情報を格納する基礎となるリレーショナル列にリライトされます。問合せは次のようにリライトされます。

SELECT VALUE(p) FROM mypurchaseorders p WHERE p.XMLDATA."Company" = 'Oracle';

注意:

XMLDATAは、基礎となるオブジェクト列への直接アクセスを可能にするXMLTypeの疑似列です。第4章「XMLTypeの操作」を参照してください。

Company列に対して次のような索引が作成されている場合、前述の問合せでは、問合せの評価にこの索引が使用されます。

CREATE INDEX company_index
  ON mypurchaseorders e (extractValue(OBJECT_VALUE, '/PurchaseOrder/Company'));

XPathリライトは、XML Schemaに基づく表、およびXML Schemaに基づくビューとXML Schemaに基づかないビューに対して発生します。この章では、XML Schemaに基づく表に関する例のみを考えます。

例7-2のSQL関数updateXMLのXPath引数は、同等のオブジェクト・リレーショナルなSQL文例7-3にリライトされます。

例7-2 UPDATEXMLでのXPathリライト

SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/User')
  FROM purchaseorder
  WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;

EXTRACTVAL
----------
SBELL

1 row selected.

UPDATE purchaseorder
  SET OBJECT_VALUE = updateXML(OBJECT_VALUE, '/PurchaseOrder/User/text()', 'SVOLLMAN')
  WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;

1 row updated.

SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/User')
  FROM purchaseorder
  WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;

EXTRACTVAL
----------
SVOLLMAN

1 row selected.

例7-3 UPDATEXMLでのXPathリライトによるリライト済オブジェクト・リレーショナル文

SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/User')
  FROM purchaseorder
  WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;

EXTRACTVAL
----------
SBELL

1 row selected.

UPDATE purchaseorder p
  SET p."XMLDATA"."userid" = 'SVOLLMAN'
  WHERE p."XMLDATA"."reference" = 'SBELL-2002100912333601PDT';

1 row updated.

SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/User')
  FROM purchaseorder
  WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;

EXTRACTVAL
----------
SVOLLMAN

1 row selected.

関連項目:

XML Schemaに基づくビューおよびXML Schemaに基づかないビューに対する他のXPathリライト例は、第3章「Oracle XML DBの使用」「XPathリライトの理解および最適化」を参照してください。

XPathリライトが行われる場合

XPathリライトは、次のSQL関数に対して行われます。

XPathリライトは、問合せ、DML文またはDDL文のいずれかの式にこれらのSQL関数が存在している場合に行われます。たとえば、関数extractValueを使用して、基礎となるリレーショナル列に対する索引を作成できます。

例7-4 SELECT文とXPathリライト

この例では、既存の発注書を戻します。

SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/Company')
  FROM mypurchaseorders x
  WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder/Item[1]/Part') = 1;

例7-5および例7-6に、基礎となる列を使用するようにリライトされる文をいくつか示します。例7-5は、CompanyOracleでないすべてのPurchaseOrder要素を削除します。

例7-5 DML文とXPathリライト

DELETE FROM mypurchaseorders x
  WHERE extractValue(OBJECT_VALUE, '/PurchaseOrder/Company') = 'Oracle Corp';

例7-6Company列に索引を作成します。

例7-6 CREATE INDEX文とXPathリライト

CREATE INDEX company_index
  ON mypurchaseorders e (extractValue(OBJECT_VALUE,'/PurchaseOrder/Company'));

Company列はオブジェクト・リレーショナル形式で格納されているため、XPathリライトが行われると、基礎となるリレーショナル列に対して索引が作成されます。この場合、SQL関数のリライトによって単純なリレーショナル列が生成されると、索引は、ファンクション索引ではなくBツリーまたは列に対するドメイン索引に変換されます。

リライトされるXPath式

通常、次のすべての条件が満たされている場合に、XPath式はリライト可能です。

表7-1に、基礎となるSQL問合せに変換できるXPath式の一部の種類を示します。

表7-1 基礎となるSQL構造体にリライトされるXPath式のサンプル・リスト

変換されるXPath式 説明

単純なXPath式:

/PurchaseOrder/@PurchaseDate

/PurchaseOrder/Company

属性自体が単純なスカラー型またはオブジェクト型である場合、オブジェクト型の属性のみに対して全検索が行われます。サポートされる軸は、child軸およびattribute軸のみです。

コレクション全検索式:

/PurchaseOrder/Item/Part

コレクション式の全検索が行われます。サポートされる軸は、child軸およびattribute軸のみです。CREATE INDEX操作の間にSQL関数が使用される場合、コレクションの全検索はサポートされません。

述語:

[Company = "Oracle"]

XPathの述語は、SQL述語にリライトされます。

リスト索引(位置指定述語):

lineitem[1]

コレクションのn番目の項目にアクセスするように索引がリライトされます。updateXMLinsertChildXMLおよびdeleteXMLの場合、索引はリライトされません。

ワイルド・カード全検索:

/PurchaseOrder/*/Part

ワイルド・カードを一意のXPathに変換できる場合(たとえば、/PurchaseOrder/Item/Part)は、パス式の最後のエントリでないかぎり、リライトされます。

descendant軸(XML Schemaに基づくデータのみ):

/PurchaseOrder//Part

ワイルド・カード式と同様です。descendent軸が一意のXPath式にマップされ、後続する要素が再帰型の定義に含まれていない場合は、descendent軸がリライトされます。ただし、再帰型の定義が存在しても、リライトできる場合があります。

Oracleで提供する拡張関数およびいくつかのXPath関数

notfloorceilingsubstringstring-lengthtranslate

ora:contains

Oracle XML DBの名前空間(http://xmlns.oracle.com/xdb)の関数はすべて、基礎となるSQL関数にリライトされます。一部のXPath関数がリライトされます。

述語内の文字列バインド変数

'/PurchaseOrder[@Id="'|| :1 || '"]'

連結演算子(||)の間にSQLバインド変数が出現し、その変数が二重引用符で囲まれている場合、そのSQLバインド変数を使用するXPath式はリライトされます。

XMLSequenceを使用するネスト解除操作

table(XMLSequence(extract(...)))

table関数コールの中でextractと組み合せて使用される場合、XMLSequenceは、Ordered Collection Tableの基礎となる構造を使用するようにリライトされます。脚注1


脚注1 tableXMLSequenceを使用するかわりに、よりわかりやすい標準のSQL/XML関数XMLTableを使用することもできます。

XPathリライトでサポートされるXML Schemaの共通構造体

complexType要素やシーケンスなどの標準的なXML Schema構造体に加え、次のXML Schema構造体もサポートされます。これは完全なリストではありません。

  • 述語にスカラー値が使用されているスカラー値のコレクション。

  • 属性を含んでいる単純型の拡張。

  • 列挙単純型。

  • ブール単純型。

  • 複合型の継承。

  • 代用グループ。

XPathリライトでサポートされないXML Schema構造体

次のXML Schema構造体はサポートされません。XPath式に次のXML Schema構造体を持つノードが含まれている場合、式はリライトされません。

  • anyコンテンツを含む要素の子にアクセスするXPath式。ノードにanyコンテンツが含まれる場合、XPathに指定された名前空間以外の名前空間をanyがターゲットとする場合を除き、式はリライトされません。any属性も同様の方法で処理されます。

  • ブール値と数値の合計など、強制変換できないデータ型の操作。

XPathリライトでサポートされる共通の記憶域構造体

次の記憶域構造体では、XPathリライトがサポートされています。

  • SQLデータ型RAWにマップされる数値単純型。

  • SQLデータ型TIMESTAMP_WITH_TZにマップされる様々な日付および時刻型。

  • 表内または表外に、およびOCTとして格納されるコレクション。

  • XML Schemaに基づく、およびXML Schemaに基づかないXMLTypeビュー、およびSQL/XMLビューでのXML関数。

XPathリライトでサポートされない記憶域構造体

次のXML Schema記憶域構造体はサポートされません。XPath式に次の記憶域構造体を持つノードが含まれている場合、式はリライトされません。

  • XML Schemaによって要素の定義の一部がSQLのCLOBインスタンスにマップされる場合、これらの要素を全検索するXPath式はリライトできません。

XPathリライトによる比較セマンティクスの変更

リライトされたXPath問合せと機能的に評価されたXPath問合せは、ほとんど差異がありません。ただし、XPathのリライトはXML Schema情報を使用してXPath述語をSQL述語に変換するため、数値以外のエンティティの比較には差異があります。

XPath 1.0で、比較演算子><>=および<=は、数値の比較のみに使用します。2つのオペランドは、比較の前に数値に変換されます。数値への変換のいずれかが失敗した場合、比較の結果としてfalseが戻ります。

たとえば、XML Schemaに基づく次のような要素定義の場合、[ShipDate < '2003-02-01']などのXPath述語は常に、機能上の評価でfalseに評価されます。

<element name="ShipDate" type="xs:date" xdb:SQLType="DATE"/>

これは、文字列'2003-02-01'を数量に変換できないためです。一方、XPathリライトでは、この述語はSQLの日付比較に変換され、ShipDateの値に従ってtrueまたはfalseに評価されます。

同様に、別のコレクション値と比較するコレクション値がある場合、XPath 1.0のセマンティクスでは、値を文字列に変換してから比較する必要があります。ただしXPathリライトでは、SQLの値を比較するためのルールを使用して比較が行われます。

比較動作の違いを抑制する場合は、問合せのヒントまたはセッション・レベルのイベントを使用してリライトを無効にできます。

XPath式のリライト方法

この項では、この章で前出の発注書XML Schemaを使用します。

例7-7 XML Schemaに基づく発注データの作成

DECLARE
  doc VARCHAR2(2000) :=
   '<schema
     targetNamespace="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
     xmlns:po="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
     xmlns="http://www.w3.org/2001/XMLSchema"
     elementFormDefault="qualified">
      <complexType name="PurchaseOrderType">
        <sequence>
          <element name="PONum" type="decimal"/>
          <element name="Company">
            <simpleType>
              <restriction base="string">
                <maxLength value="100"/>
              </restriction>
            </simpleType>
          </element>
          <element name="Item" maxOccurs="1000">
            <complexType>
              <sequence>
                <element name="Part">
                  <simpleType>
                    <restriction base="string">
                      <maxLength value="20"/>
                    </restriction>
                  </simpleType>
                </element>
                <element name="Price" type="float"/>
              </sequence>
            </complexType>
          </element>
        </sequence>
      </complexType>
      <element name="PurchaseOrder" type="po:PurchaseOrderType"/>
    </schema>';
BEGIN
  DBMS_XMLSCHEMA.registerSchema(
    'http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd', doc);
END;
/

XML Schema登録では、内部的なSQLデータ型が作成されます。これによって、XML値を格納する表およびItemを格納するOrdered Collection Tableを作成できるようになりました。

CREATE TABLE mypurchaseorders OF XMLType
  XMLSchema "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
  ELEMENT "PurchaseOrder"
  VARRAY XMLDATA."Item" STORE AS TABLE item_nested;

Table created

次に、発注書をこの表に挿入します。

INSERT INTO mypurchaseorders
  VALUES(
   XMLType(
     '<PurchaseOrder
          xmlns="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation
             = "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd
                http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd">
        <PONum>1001</PONum>
        <Company>Oracle Corp</Company>
        <Item>
          <Part>9i Doc Set</Part>
          <Price>2550</Price>
        </Item>
        <Item>
          <Part>8i Doc Set</Part>
          <Price>350</Price>
        </Item>
      </PurchaseOrder>'));

XML Schemaでは順序の保持についての情報が指定されていないため、デフォルト動作では、順序およびDOM再現性が保持されます。したがって、型には、ノードの順序を保持し、コメントや処理命令などの追加項目を取得するのに必要な追加情報を格納するためのSYS_XDBPD$(PD)属性が含まれます。

オブジェクト属性SYS_XDBPD$には、要素の有無を示す情報(入力ドキュメントに要素が存在したかどうか)も保持されます。simpleType要素の場合は単純なリレーショナル列にマップされるため、この情報が必要です。空のsimpleType要素と欠落しているsimpleType要素の両方が列のNULL値にマップされます。この2つを区別するには、SYS_XDBPD$属性を使用できます。XPathリライト・メカニズムでは属性SYS_XDBPD$の有無が考慮され、問合せが適切にリライトされます。

この表には、実際のデータを格納するpurchaseorder_tという型の疑似列XMLDATAが含まれます。

XPath式のリライト: 日付型およびパス式のマッピング

この項では、XPath式からSQLデータ型とパス式へのマッピングについて説明します。

単純なXPath式のマッピング

単純なXPath式のリライトは、その式に対応するSQL列へのアクセスを伴います(表7-2を参照)。

表7-2 XML Schema purchaseOrderの単純なXPathマッピング

XPath式 マップ先

/PurchaseOrder

XMLDATA

/PurchaseOrder/@PurchaseDate

XMLDATA."PurchaseDate"

/PurchaseOrder/PONum

XMLDATA."PONum"

/PurchaseOrder/Item

コレクションXMLDATA."Item"の要素

/PurchaseOrder/Item/Part

コレクションXMLDATA."Item"内の属性"Part"


simpleType要素のマッピング

XPath式には、要素のテキスト・ノード(コンテンツ)をターゲットとするtext()ノード・テストを含めることができます。リライトによって、この式は基礎となるリレーショナル列に直接マップされます。たとえば、XPath式/PurchaseOrder/PONum/text()は、SQL列XMLDATA."PONum"に直接マップされます。

PONum列のNULL値は、入力ドキュメントにtext()ノード・テストが存在しないか、または要素自体が欠落しているため、テキスト値が使用できないことを意味します。列がNULLの場合、SYS_XBDPD$属性で要素の有無を確認する必要はありません。

XPath /PurchaseOrder/PONumも、SQL列XMLDATA."PONum"にマップされます。ただし、この場合、XPathリライトで、XMLDATA列のSYS_XDBPD$属性を使用して要素自体の有無を確認する必要があります。

述語のマッピング

XPath述語は、SQL述語式にマップされます。比較では、XPath 1.0セマンティクスにでなくSQLの比較規則が使用されます。「XPathリライトによる比較セマンティクスの変更」を参照してください。

たとえば、XPath式/PurchaseOrder[PONum=1001 and Company = "Oracle Corp"]の述語はSQL述語(XMLDATA."PONum" = 20 AND XMLDATA."Company" = "Oracle Corp")にマップされます。

例7-8 述語のマッピング

この問合せは、構造化された(オブジェクト・リレーショナルな)問合せにリライトされます。

SELECT extract(OBJECT_VALUE, '/PurchaseOrder/Item').getCLOBval()
  FROM mypurchaseorders p
  WHERE existsNode(OBJECT_VALUE,
                   '/PurchaseOrder[PONum=1001 AND Company = "Oracle Corp"]') = 1;

コレクション述語のマッピングXPath式に、リレーショナル・コレクション式が含まれていることがあります。Xpath 1.0では、これらの式は要素の有無の確認として処理されます。少なくとも1つのコレクション・メンバーが式に含まれている場合、その式はtrueです。

例7-9 コレクション述語のマッピング

このXPath式のコレクション述語には、リレーショナルの大なり演算子(>)が含まれています。

/PurchaseOrder[Items/Price > 200]

これは、次のSQLコレクション式にマップされます。

exists(SELECT NULL FROM table(XMLDATA."Item") x WHERE x."Price" > 200)

この例では、コレクションがスカラー値に関連付けられています。2つのコレクションに関連がある場合、リライトは複雑になります。たとえば、次のXPath式では、LineItemsShippedItemsはいずれもコレクションです。

/PurchaseOrder[LineItems = ShippedItems]

この場合、この2つのコレクションからのノードのいずれかの組合せが等価性を満たしていれば、その述語が等価性を満たしていると判断されます。

例7-10 EXISTSNODEを使用したコレクション述語のマッピング

PurchaseorderPricePartの数値が同じであるItemが存在するかどうかを確認するXPath、/PurchaseOrder[Items/Price = Items/Part]を考えてみます。これは、次のSQLコレクション式にマップされます。

EXISTS (SELECT NULL
          FROM table(XMLDATA."Item") x
          WHERE EXISTS (SELECT NULL FROM table(XMLDATA."Item") y
                                    WHERE  y."Part" = x."Price"))

次の問合せは、構造化された問合せにリライトされます。

SELECT extract(OBJECT_VALUE, '/PurchaseOrder/Item').getCLOBval()
  FROM  mypurchaseorders p
  WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Item/Price = Item/Part]') = 1;

コレクション全検索でのドキュメント内の順序の保持

ほとんどのリライトでは、元のドキュメント内の順序が保持されます。ただし、SQLでは副問合せの結果における順序の保持が保証されないため、SQL関数extractを使用してコレクションから要素を選択すると、ノードの順序がドキュメント内の順序と異なる場合があります。

例7-11 コレクション全検索でのドキュメント内の順序の保持

次に例を示します。

SELECT extract(OBJECT_VALUE, '/PurchaseOrder/Item[Price>2100]/Part')
  FROM mypurchaseorders p;

この問合せは、副問合せを使用するようにリライトされます。

SELECT (SELECT XMLAgg(XMLForest(x."Part" AS "Part"))
          FROM table(XMLDATA."Item") x WHERE  x."Price" > 2100)
  FROM mypurchaseorders p;

ほとんどの場合、集計の結果はコレクション要素と同じ順序になりますが、これが保証されているわけではありません。したがって、結果がドキュメント順序とは異なる場合もあります。

スキーマベース: コレクションの位置

XPath式で、コレクションの特定位置にある要素にアクセスすることもできます。たとえば、/PurchaseOrder/Item[1]/Partは、コレクションの最初のItemを抽出し、その中のPart属性にアクセスするようにリライトされます。

コレクションがVARRAY値として格納されている場合は、この操作によって元のドキュメント内の順序でノードが取得されます。コレクションが順序付けられていない表に格納されている場合、順序は判別不能です。

条件を満たすことのできないXPath式

XPath式には、入力ドキュメントに含めることができないノードに対する参照が含まれる場合があります。式のこのような部分は、リライト時にSQLのNULL値にマップされます。たとえば、/PurchaseOrder/ShipAddressというXPath式は、purchaseorder.xsdというXML Schemaに準拠するインスタンス・ドキュメントの条件を満たすことができません。これは、スキーマでPurchaseOrderShipAddress要素が許可されないためです。したがって、この式はSQLのNULLリテラルにマップされます。

名前空間の取扱い

名前空間は、関数ベースの評価と同じ方法で処理されます。XML Schemaに基づく文書の場合、関数(existsNodeextractなど)によって名前空間パラメータが指定されないと、スキーマのターゲットの名前空間がXPath式のデフォルトの名前空間として使用されます。

例7-12 名前空間の処理

たとえば、SQL関数によって名前空間の接頭辞およびマッピングが明示的に指定されない場合、XPath式/PurchaseOrder/PONumは、xmlns:a= "http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd/a:PurchaseOrder/a:PONumとして処理されます。別の例を示します。

SELECT * FROM mypurchaseorders p
  WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder/PONum') = 1;

これは、次の問合せと同等の結果を戻します。

SELECT *
  FROM mypurchaseorders p
  WHERE existsNode(
          OBJECT_VALUE,
          '/PurchaseOrder/PONum',
          'xmlns="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd')
        = 1;

XPathリライトを実行すると、特定の要素に対する名前空間はXML Schema定義の名前空間と一致します。XML SchemaにelementFormDefault = "qualified"が含まれる場合、XPath式の各ノードは名前空間をターゲットとする必要があります(これは、デフォルトの名前空間の指定を使用するか、または各ノードに名前空間の接頭辞を付けることで実行できます)。

elementFormDefaultが非修飾(デフォルト)である場合、名前空間を定義するノードのみに接頭辞が含まれる必要があります。たとえば、purchaseorder.xsdの要素形式が非修飾の場合は、existsNode式を次のようにリライトする必要があります。

existsNode(
  OBJECT_VALUE,
  '/a:PurchaseOrder/PONum',
  'xmlns:a="http://xmlns.oracle.com/xdb/documentation/purchaseOrder.xsd")
= 1;

注意:

elementFormDefaultが非修飾である場合、前述の例のexistsNode式で名前空間パラメータを省略すると、各ノードがデフォルトでターゲットの名前空間に設定されます。これは、XML Schema定義に一致しないために、結果が戻されない場合があります。これは、関数がリライトされるかどうかに関係ありません。

日付書式の変換

dategMonthおよびgDateの日付データ型の書式は、XML SchemaとSQLで異なります。このようなデータ型の列に対する文字列値が式に含まれていると、リライトによってXML形式の文字列が自動的に挿入され、文字列値が正しく変換されます。このため、date列に指定された文字列値は、SQLのDATE書式ではなく、XMLのdate書式に一致している必要があります。

例7-13 日付書式の変換

たとえば、式[@PurchaseDate="2002-02-01"]は単にXMLDATA."PurchaseDate"="2002-02-01"としてはリライトされません。これは、SQLのデフォルトの日付書式がYYYY-MM-DDでないためです。したがって、XPathのリライト時に、XML形式の文字列が追加され、テキスト値がDATEデータ型に正しく変換されます。前述の述語は、次のとおりリライトされます。

XMLDATA."PurchaseDate" = TO_DATE("2002-02-01","SYYYY-MM-DD");

同様に、これらの列を(extractなどの関数に必要な)テキスト値に変換する際に、XML形式の文字列が追加されてXMLと同じ日付書式に変換されます。

スカラー値を含む属性および要素の有無の確認

SQL関数existsNodeは、XPathで指定されているノードの有無を確認します。関数extractは、XPathで指定されているノードを戻します。Oracle XML DBは、simpleType要素に対して、およびexistsNode式で使用されている属性に対して、特別なチェックを実行する必要があります。これは、SQL列の値が単独では属性またはsimpleType要素が欠落していたり、空であることを識別できないためです。NULLのSQL列は、いずれも表すことができます。中間要素の場合は、ユーザー定義のSQLデータ型によって、その要素が欠落していること、または空であることが示されるため、これらの特別なチェックは不要です。

たとえば、次の式について考えてみます。

existsNode(OBJECT_VALUE, '/PurchaseOrder/PONum/text()') = 1;

問合せがノードのテキスト値のみを対象としているため、この式は次のようにリライトされます。

(p.XMLDATA."PONum" IS NOT NULL)

次に、text()ノード・テストのない式について考えてみます。

existsNode(OBJECT_VALUE, '/PurchaseOrder/PONum') = 1;

この場合、Oracle XML DBは、親ノードのSYS_XDBPD$属性をチェックして、要素が空または欠落しているかどうかを判断する必要があります。このチェックは内部で実行されます。これは、次のような擬似コードで表すことができます。

node_exists(p.XMLDATA."SYS_XDBPD$", "PONum")

擬似関数node_existsは、説明のためのみに使用しています。これは、最初の引数である位置指定ディスクリプタ(PD)列(SYS_XDBPD$)を使用して2番目の引数(要素または属性)のノードが存在するかどうかを判別する、Oracle XML DBの実装を表しています。2番目の引数のノードが存在する場合はtrueを、存在しない場合はfalseを戻します。

extract式の場合は、属性および要素の両方に対してこのチェックを実行する必要があります。extract(OBJECT_VALUE, '/PurchaseOrder/PONum')という形式の式は、次のような擬似コードにマップされます。

CASE WHEN node_exists(p.XMLDATA.SYS_XDBPD$", "PONum")
       THEN XMLElement("PONum", p.XMLDATA."PONum")
       ELSE NULL END;

注意:

existsNodeまたはextract式を記述する場合は、このオーバーヘッドに注意してください。このオーバーヘッドを回避するには、XPath式のtext()ノード・テストを使用するか、extractValueを使用してノードの値のみを取得するか、あるいは親ノードのDOM再現性を無効にします。DOM再現性は、要素定義のmaintainDOM属性の値をfalseに設定することで無効にできます。無効にした場合、空の要素および属性は欠落しているとして処理されます。

XPathリライトの診断

この項では、XPath式が実際にリライトされているかどうかを判断するテクニックを紹介します。

XPathリライトでのEXPLAIN PLANの使用

この項では、EXPLAIN PLANを使用して、XPathリライト後に問合せ計画を調べる方法について説明します。EXPLAIN PLANを使用してXPathリライトを最適化する方法の詳細は、「XPathリライトの理解および最適化」を参照してください。

問合せ評価計画で、適用可能な索引が選択されずにSQL関数(existsNodeextractなど)の存在が示された場合は、リライトが発生しなかったことがわかります。その後、イベントを使用して、XPathリライトが発生しなかった理由を理解できます。「XPathでのイベントの使用」を参照してください。

たとえば、表mypurchaseordersを使用して、EXPLAIN PLANの使用を確認できます。PurchaseOrderCompany要素に対して索引を作成し、計画の違いを確認します。

CREATE INDEX company_index ON mypurchaseorders
       (extractValue(OBJECT_VALUE,'/PurchaseOrder/Company'));

Index created.

EXPLAIN PLAN FOR
  SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/PONum')
    FROM mypurchaseorders
    WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Company="Oracle"]') = 1;

Explained.

SELECT PLAN_TABLE_OUTPUT
  FROM table(DBMS_XPLAN.display('plan_table', NULL, 'serial'))
/

PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------
| Id  | Operation                    | Name             | Rows | Bytes | Cost |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                  |      |       |      |
|   1 |  TABLE ACCESS BY INDEX ROWID | MYPURCHASEORDERS |      |       |      |
|*  2 |   INDEX RANGE SCAN           | COMPANY_INDEX    |      |       |      |
-------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("MYPURCHASEORDERS"."SYS_NC00010$"='Oracle')

このEXPLAIN PLANでは、述語が内部列を使用しており、Company要素に対する索引を選択していることを確認できます。これは、問合せが基礎となるリレーショナル列にリライトされたことを示しています。

次の問合せは、文字列型であるCompany要素に対して算術演算を実行しようとしています。これはリライトされません。EXPLAIN PLANは述語に元のexistsNode式が含まれていることを示しています。また、述語はリライトされないため、索引レンジ・スキャンではなく、全表スキャンが使用されます。

EXPLAIN PLAN FOR
  SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/PONum')
    FROM mypurchaseorders
    WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Company+PONum="Oracle"]') = 1;

Explained.

SELECT PLAN_TABLE_OUTPUT
  FROM table(DBMS_XPLAN.display('plan_table', NULL, 'serial'))/

PLAN_TABLE_OUTPUT
-----------------------------------------------------------
| Id  | Operation          | Name
-----------------------------------------------------------
|   0 | SELECT STATEMENT   |
|*  1 |  FILTER            |
|   2 |   TABLE ACCESS FULL| MYPURCHASEORDERS
|*  3 |   TABLE ACCESS FULL| ITEM_NESTED
-----------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(EXISTSNODE(SYS_MAKEXML('C6DB2B4A1A3B0
              6CDE034080020E5CF39',2300,"MYPURCHASEORDERS"."XMLEXTRA",
              "MYPURCHASEORDERS"."XMLDATA"),
      '/PurchaseOrder[Company+PONum="Oracle"]')=1)
   3 - filter("NESTED_TABLE_ID"=:B1)

XPathでのイベントの使用

イベントは、初期化ファイルに設定するか、またはALTER SESSION文を使用して各セッションに設定できます。XMLイベントを使用すると、機能上の評価やXPathリライト・メカニズムを無効にしたり、診断トレースを印刷できます。

機能上の評価の無効化(イベント19021)

このイベントを使用可能にすることで、XML関数がリライトされずに機能上の評価が行われる場合には、常にエラーが発行されるようにできます。このような関数が実行されると、エラー「ORA-19022: XML XPath機能は使用できません」が発行されます。また、このイベントを使用して、関数に対する機能上の評価を選択して無効にすることもできます。表7-3に、様々なイベント・レベルおよび対応する動作をリストします。

表7-3 イベントのレベルおよび動作

イベント 機能上の評価が無効になる関数

レベル0x1

すべてのXML関数

レベル0x2

extract

レベル0x4

existsNode

レベル0x8

transform

レベル0x10

extractValue

レベル0x20

updateXML

レベル0x40

insertXMLbefore

レベル0x80

appendChildXMl

レベル0x100

deleteXML

レベル0x200

XMLSequence

レベル0x4000

insertChildXML

レベル0x8000

XMLQuery


次に例を示します。

ALTER SESSION SET EVENTS '19021 trace name context forever, level 1';

この場合、前述のすべてのXML演算子の評価が無効になります。したがって、リライトされていない前述の問合せを実行すると、問合せの実行でエラーが発生します。

SELECT OBJECT_VALUE FROM mypurchaseorders
  WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Company+PONum="Oracle"]')=1 ;

ERROR:
ORA-19022: XML XPath functions are disabled

リライトが発生しない理由のトレース

8192(0x2000)レベルのイベント19027を使用すると、特定のXML関数がリライトされていない理由を示すトレースをダンプできます。たとえば、前述の問合せがリライトされなかった理由を調べる場合は、イベントを設定してEXPLAIN PLANを実行します。

ALTER SESSION SET EVENTS '19027 TRACE NAME CONTEXT FOREVER, LEVEL 8192';

Session altered.

EXPLAIN PLAN FOR
  SELECT OBJECT_VALUE FROM mypurchaseorders
    WHERE existsNode(OBJECT_VALUE, '/PurchaseOrder[Company+100="Oracle"]') = 1;

Explained.

次の記述は、算術関数に対する数値以外の入力が原因でXPathのリライトが生じなかったことを示すOracleのトレース・ファイルです。

NO REWRITE
        XPath ==> /PurchaseOrder[Company+PONum = "Oracle"]        Reason ==> non numeric inputs to arith{2}{4}

個別のSQL関数のXPathリライト

この項では、SQL関数existsNodeextractValueextractXMLSequenceupdateXMLinsertChildXMLおよびdeleteXMLに対するXPathリライトについて詳しく説明します。existsNodeまたはextractを使用する特定タイプの操作で発生するオーバーヘッドと、それを回避する方法について説明します。

これらのSQL関数を使用する更新では、通常、XML文書のコピーが更新されてから、新しく変更された文書で文書全体が置換されます。

XMLTypeデータがXML Schemaマッピングを使用してオブジェクト・リレーショナル形式で格納されている場合は、文書の断片がインプレース変更されるように更新が最適化されます。たとえば、PONum要素を更新する場合、メモリー内で文書全体を生成した後に更新を実行するのではなく、列XMLDATA."PONum"が直接更新されるようにリライトできます。

更新時にこのようなリライト最適化を使用するには、関数updateXMLinsertChildXMLおよびdeleteXMLがそれぞれ別の条件を満たしている必要があります。前述のすべての条件が満たされる場合、ファンクション式は単純なリレーショナル更新にリライトされます。次に例を示します。

UPDATE purchaseorder_table
  SET OBJECT_VALUE =
      updateXML(OBJECT_VALUE,
                '/PurchaseOrder/@PurchaseDate', '2002-01-02',
                '/PurchaseOrder/PONum/text()', 2200);

この更新操作は、次のようにリライトされます。

UPDATE purchaseorder_table p
  SET p.XMLDATA."PurchaseDate" = TO_DATE('2002-01-02', 'SYYYY-MM-DD'),
      p.XMLDATA."PONum" = 2100;

EXISTSNODEのXPathリライト

XPath引数が空でないノード(テキスト、要素または属性)のシーケンスをターゲットにしている場合、SQL関数existsNode1を戻します。そうでない場合は、0(ゼロ)を戻します。値の判別方法は、XPath引数でターゲットになっているノードの種類によって異なります。

  • XPath引数が(ノード・テストtext()を使用する)テキスト・ノードまたはcomplexType要素ノードをターゲットにしている場合、Oracle XML DBは、要素のコンテンツのデータベース表示がNULLであるかどうかをチェックするのみです。

  • それ以外の場合、XPath引数はsimpleType要素ノードまたは属性ノードをターゲットにしています。Oracle XML DBは、位置指定ディスクリプタ属性SYS_XDBPD$を使用してノードの有無を確認します。SYS_XDBPD$属性が存在しない場合は、列がNULLかどうかを調べることによってノードの有無が判断されます。

ドキュメント内の順序が保持されるEXISTNODEのマッピング

表7-4に、ドキュメント内の順序が保持される(SYS_XDBPD$が存在し、スキーマ・ドキュメントでmaintainDOM = "true"が設定されている)場合の、SQL関数existsNodeでの様々なXPath式のマッピングを示します。

表7-4 ドキュメント内の順序が保持されるEXISTSNODEのXPathマッピング

XPath式 マップ先
/PurchaseOrder
CASE WHEN XMLDATA IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/@PurchaseDate
CASE WHEN node_exists脚注1 (XMLDATA.SYS_XDBPD$, 'PurchaseDate')
       THEN 1 ELSE 0 END
/PurchaseOrder/PONum
CASE WHEN node_exists脚注1(XMLDATA.SYS_XDBPD$, 'PONum')
       THEN 1 ELSE 0 END
/PurchaseOrder[PONum = 2100]
CASE WHEN XMLDATA."PONum"=2100 THEN 1 ELSE 0
/PurchaseOrder[PONum = 2100]/@PurchaseDate
CASE WHEN XMLDATA."PONum"=2100
      AND node_exists脚注1(XMLDATA.SYS_XDBPD$, 'PurchaseDate')
       THEN 1 ELSE 0 END
/PurchaseOrder/PONum/text()
CASE WHEN XMLDATA."PONum" IS NOT NULL THEN 1 ELSE 0
/PurchaseOrder/Item
CASE WHEN exists(SELECT NULL FROM table(XMLDATA."Item") x
                   WHERE value(x) IS NOT NULL)
       THEN 1 ELSE 0 END
/PurchaseOrder/Item/Part
CASE WHEN exists(SELECT NULL FROM table(XMLDATA."Item") x
                   WHERE node_exists脚注1(x.SYS_XDBPD$, 'Part'))
       THEN 1 ELSE 0 END
/PurchaseOrder/Item/Part/text()
CASE WHEN exists(SELECT NULL FROM table(XMLDATA."Item") x
                   WHERE x."Part" IS NOT NULL)
       THEN 1 ELSE 0 END

脚注1 擬似関数node_existsは、説明のためのみに使用しています。これは、最初の引数であるPD列を使用して2番目の引数のノードが存在するかどうかを判断する、Oracle XML DBの実装を表しています。2番目の引数のノードが存在する場合はtrueを、存在しない場合はfalseを戻します。

例7-14 ドキュメント内の順序が保持されるEXISTSNODEのマッピング

この問合せでは、前述のマッピングを使用して、発注1001に価格が2000を超える部品が存在するかどうかを確認します。

SELECT count(*)
  FROM purchaseorder
  WHERE existsNode(OBJECT_VALUE,
                   '/PurchaseOrder[PONum=1001 and Item/Price > 2000]') = 1;

この問合せは、次のようにリライトされます。

SELECT count(*)
  FROM  purchaseorder p
  WHERE CASE WHEN p.XMLDATA."PONum" = 1001
              AND exists(SELECT NULL FROM table(XMLDATA."Item") p
                           WHERE  p."Price" > 2000 ))
               THEN 1
               ELSE 0
        END = 1;

このCASE式は、さらに定数関係式によって最適化されます。問合せは、次のように再作成されます。

SELECT count(*)
  FROM purchaseorder p
  WHERE p.XMLDATA."PONum"=1001
    AND exists(SELECT NULL FROM table(p.XMLDATA."Item") x
                 WHERE  x."Price" > 2000);

Part列およびPONum列にリレーショナル索引が存在する場合、そのリレーショナル索引を使用して評価が行われます。

ドキュメント内の順序が保持されないEXISTSNODEのマッピング

位置指定ディスクリプタ属性SYS_XDBPD$が存在しない場合(つまり、XML SchemaでmaintainDOM = "false"が指定されている場合)、NULLスカラー列が、存在しないsimpleType要素にマップされます。その場合、属性SYS_XDBPD$を使用してノードの有無を確認する必要はありません。表7-5に、SYS_XDBPD$属性がない場合のexistsNodeのマッピングを示します。

表7-5 ドキュメント内の順序が保持されないEXISTSNODEのXPathマッピング

XPath式 マップ先
/PurchaseOrder
CASE WHEN XMLDATA IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/@PurchaseDate
CASE WHEN XMLDATA.'PurchaseDate' IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/PONum
CASE WHEN XMLDATA."PONum" IS NOT NULL THEN 1   ELSE 0 END
/PurchaseOrder[PONum = 2100]
CASE WHEN XMLDATA."PONum" = 2100 THEN 1 ELSE 0 END
/PurchaseOrder[PONum = 2100]/@PurchaseOrderDate
CASE WHEN XMLDATA."PONum" = 2100
      AND XMLDATA."PurchaseDate" NOT NULL
       THEN 1 ELSE 0 END
/PurchaseOrder/PONum/text()
CASE WHEN XMLDATA."PONum" IS NOT NULL THEN 1 ELSE 0 END
/PurchaseOrder/Item
CASE WHEN exists(SELECT NULL FROM table(XMLDATA."Item") x
                   WHERE value(x) IS NOT NULL)
       THEN 1 ELSE 0 END
/PurchaseOrder/Item/Part
CASE WHEN exists(SELECT NULL FROM table(XMLDATA."Item") x
                   WHERE x."Part" IS NOT NULL)
       THEN 1 ELSE 0 END
/PurchaseOrder/Item/Part/text()
CASE WHEN exists(SELECT NULL FROM table(XMLDATA."Item") x
                   WHERE x."Part" IS NOT NULL)
       THEN 1 ELSE 0 END

EXTRACTVALUEのXPathリライト

SQL関数extractValueは、関数extractを使用してテキスト・ノードおよび属性を抽出し、次にメソッドgetStringVal()またはgetNumberVal()を使用してスカラー・コンテンツを取得するためのショートカットです。関数extractValueは、スカラー値を持つ要素の属性ノードまたはテキスト・ノードの値を戻します。関数extractValueは、複数の値またはcomplexType要素を戻すXPath式を処理できません。

表7-6に、関数extractValueでの様々なXPath式のマッピングを示します。XPath式が要素をターゲットとしている場合は、extractValueによって要素のテキスト・ノードが取得されます。たとえば、/PurchaseOrder/PONumおよび/PurchaseOrder/PONum/text()extractValueによって同じ方法で処理されます。どちらも、PONumのスカラー・コンテンツを取得します。

表7-6 EXTRACTVALUEのXPathマッピング

XPath式 マップ先
/PurchaseOrder

サポートされていません。関数extractValueで取得できるのは、スカラー要素および属性の値のみです。

/PurchaseOrder/@PurchaseDate
XMLDATA."PurchaseDate"
/PurchaseOrder/PONum
XMLDATA."PONum"
/PurchaseOrder[PONum = 2100]
(SELECT TO_XML(x.XMLDATA) FROM DUAL
   WHERE x."PONum" = 2100)
/PurchaseOrder[PONum =
               2100]/@PurchaseDate
(SELECT x.XMLDATA."PurchaseDate") FROM DUAL
   WHERE x."PONum" = 2100)
/PurchaseOrder/PONum/text()
XMLDATA."PONum"
/PurchaseOrder/Item

サポートされていません。関数extractValueで取得できるのは、スカラー要素および属性の値のみです。

/PurchaseOrder/Item/Part

サポートされていません。関数extractValueは複数のスカラー値を取得できません。

/PurchaseOrder/Item/Part/text()

サポートされていません。関数extractValueは複数のスカラー値を取得できません。


例7-15 EXTRACTVALUEのリライト

次のSQL問合せについて考えてみます。

SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/PONum') FROM purchaseorder
  WHERE extractValue(OBJECT_VALUE, '/PurchaseOrder/PONum') = 1001;

この問合せは、次のようにリライトされます。

SELECT p.XMLDATA."PONum" FROM purchaseorder p WHERE p.XMLDATA."PONum" = 1001;

これは単純なスカラー列にリライトされるため、属性PONumに対する索引があれば、問合せの条件を満たすためにそれを使用できます。

EXTRACTVALUEを使用した索引の作成

関数extractValueは、索引式で使用できます。式がスカラー列にリライトされると、索引はファンクション索引ではなくBツリー索引に変換されます。

例7-16 EXTRACTVALUEを使用した索引の作成

CREATE INDEX my_po_index ON purchaseorder
  (extractValue(OBJECT_VALUE, '/PurchaseOrder/Reference);

これは、次のようにリライトされます。

CREATE INDEX my_po_index ON purchaseorder x (x.XMLDATA."Reference");

これによって、通常のBツリー索引が生成されます。ファンクション索引とは異なり、同じ索引で次のような列をターゲットとする問合せの条件を満たすことができるようになります。

existsNode(OBJECT_VALUE, '/PurchaseOrder[Reference="SBELL-2002100912333601PDT"]') = 1;

EXTRACTのXPathリライト

SQL関数extractは、XPathの結果をXMLとして取得します。テキスト・ノードが含まれるXpath式の場合、extractは同様にextractValueにリライトされます。

ドキュメント内の順序が保持されるEXTRACTのマッピング

表7-7に、ドキュメント内の順序が保持される場合(SYS_XDBPD$が存在し、XML SchemaドキュメントでmaintainDOM = "true"が設定されている場合)の、extract式内部の様々なXPath式のマッピングを示します。

表7-7 ドキュメント内の順序が保持されるEXTRACTのXPathマッピング

XPath マップ先
/PurchaseOrder
XMLForest(XMLDATA AS "PurchaseOrder")
/PurchaseOrder/@PurchaseDate
CASE WHEN node_exists脚注1 (XMLDATA.SYS_XDBPD$, 'PurchaseDate')
       THEN XMLElement("", XMLDATA."PurchaseDate") ELSE NULL END;
/PurchaseOrder/PONum
CASE WHEN node_exists脚注1(XMLDATA.SYS_XDBPD$, 'PONum')
       THEN XMLElement("PONum", XMLDATA."PONum") ELSE NULL END
/PurchaseOrder[PONum = 2100]
SELECT XMLForest(XMLDATA as "PurchaseOrder") FROM DUAL
  WHERE XMLDATA."PONum" = 2100
/PurchaseOrder
[PONum = 2100]/@PurchaseDate
SELECT CASE WHEN node_exists脚注1(XMLDATA.SYS_XDBPD$, 'PurchaseDate')
              THEN XMLElement("", XMLDATA."PurchaseDate")
              ELSE NULL END
  FROM DUAL WHERE XMLDATA."PONum" = 2100
/PurchaseOrder/PONum/text()
XMLElement("", XMLDATA."PONum")
/PurchaseOrder/Item
SELECT XMLAgg(XMLForest(value(it) AS "Item"))
  FROM table(XMLDATA."Item") it
/PurchaseOrder/Item/Part
SELECT XMLAgg(CASE WHEN node_exists脚注1(p.SYS_XDBPD$, 'Part')
                     THEN XMLForest(p."Part" AS "Part")
                     ELSE NULL END)
  FROM table(XMLDATA."Item") p
/PurchaseOrder/Item/Part/text()
SELECT XMLAgg(XMLElement("", p."Part"))
  FROM table(XMLDATA."Item") p

脚注1 擬似関数node_existsは、説明のためのみに使用しています。これは、最初の引数であるPD列を使用して2番目の引数のノードが存在するかどうかを判断する、Oracle XML DBの実装を表しています。2番目の引数のノードが存在する場合はtrueを、存在しない場合はfalseを戻します。

例7-17 ドキュメント内の順序が保持されるEXTRACTのXPathマッピング

表7-7に示すマッピングを使用して、発注書に価格が2000を超える部品が含まれるPONum要素を抽出する次の問合せを考えてみます。

SELECT extract(OBJECT_VALUE, '/PurchaseOrder[Item/Part > 2000]/PONum')
  FROM purchaseorder_table;

この問合せは、次のようになります。

SELECT (SELECT CASE WHEN node_exists(p.XMLDATA.SYS_XDBPD$, 'PONum')
                      THEN XMLElement("PONum", p.XMLDATA."PONum")
                      ELSE NULL END
          FROM DUAL
          WHERE exists(SELECT NULL FROM table(XMLDATA."Item") p
                         WHERE  p."Part" > 2000))
  FROM purchaseorder_table p;

ドキュメント内の順序が保持されないEXTRACTのマッピング

属性SYS_XDBPD$が存在しない場合(つまり、XML SchemaでmaintainDOM = "false"が指定されている場合)、NULLスカラー列が、存在しないsimpleType要素にマップされます。したがって、属性SYS_XDBPD$を使用してノードの有無を確認する必要はありません。表7-8に、SYS_XDBPD$がない場合の関数existsNodeのマッピングを示します。

表7-8 ドキュメント内の順序が保持されないEXTRACTのXPathマッピング

XPath マップ先
/PurchaseOrder
XMLForest(XMLDATA AS "PurchaseOrder")
/PurchaseOrder/@PurchaseDate
XMLForest(XMLDATA."PurchaseDate" AS "PurchaseDate")
/PurchaseOrder/PONum
XMLForest(XMLDATA."PONum" AS "PONum")
/PurchaseOrder[PONum = 2100]
SELECT XMLForest(XMLDATA AS "PurchaseOrder")
  FROM DUAL WHERE XMLDATA."PONum" = 2100
/PurchaseOrder
  [PONum = 2100]/@PurchaseDate
SELECT XMLForest(XMLDATA."PurchaseDate" AS "PurchaseDate "")
  FROM DUAL WHERE XMLDATA."PONum" = 2100
/PurchaseOrder/PONum/text()
XMLForest(XMLDATA.PONum AS "")
/PurchaseOrder/Item
SELECT XMLAgg(XMLForest(value(p) AS "Item")
  FROM table(XMLDATA."Item") p
/PurchaseOrder/Item/Part
SELECT XMLAgg(XMLForest(p."Part" AS "Part")
  FROM table(XMLDATA."Item") p
/PurchaseOrder/Item/Part/text()
SELECT XMLAgg(XMLForest(p. "Part" AS "Part"))
  FROM table(XMLDATA."Item") p

XMLSEQUENCEのXPathリライト

SQL関数XMLSequenceをSQL関数extractおよびtableと組み合せて使用すると、XMLのコレクション値をネスト解除できます。脚注1 XML Schemaに基づく記憶域で使用されている場合、これらの関数も、基礎となるリレーショナル・コレクション記憶域にアクセスするようにリライトされます。

たとえば、この問合せは、全品目の価格と部品番号をリレーショナル形式で取得します。

SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/PONum') AS ponum,
       extractValue(value(it), '/Item/Part') AS part,
       extractValue(value(it), '/Item/Price') AS price
  FROM purchaseorder,
       table(XMLSequence(extract(OBJECT_VALUE, '/PurchaseOrder/Item'))) it;

PONUM PART                 PRICE
----- -------------------- ---------
1001  9i Doc Set           2550
1001  8i Doc Set            350

この例では、SQL関数extractは、Item要素のリストを含むフラグメントを戻します。関数XMLSequenceは、Item要素ごとに、このフラグメントをXMLType値のコレクションに変換します。関数tableは、コレクションの要素をXMLTypeの行に変換します。tableから戻されたXMLデータは、Part要素およびPrice要素の抽出に使用されます。

関数extractおよびXMLSequenceを適用すると、Ordered Collection Table(OCT)のitem_nested上の単純なSELECT操作にリライトされます。

EXPLAIN PLAN
  FOR SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/PONum') AS ponum,
             extractValue(value(it) , '/Item/Part') AS part,
             extractValue(value(it), '/Item/Price') AS price
        FROM purchaseorder,
             table(XMLSequence(extract(OBJECT_VALUE, '/PurchaseOrder/Item'))) it;

Explained

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------
| Id  | Operation                     | Name             |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |
|   1 |  NESTED LOOPS                 |                  |
|   2 |   TABLE ACCESS FULL           | ITEM_NESTED      |
|   3 |   TABLE ACCESS BY INDEX ROWID | PURCHASEORDER    |
|*  4 |    INDEX UNIQUE SCAN          | SYS_C002973      |
----------------------------------------------------------------------------

Predicate Information (identified by operation id)
--------------------------------------------------
   4 - access("NESTED_TABLE_ID"="SYS_ALIAS_1"."SYS_NC0001100012$")

EXPLAIN PLANの出力は、オプティマイザがOCTのitem_nestedと表purchaseorderとの間の単純なネステッド・ループ結合を使用できることを示しています。Item値をさらに問い合せたり、OCTに適切な索引を作成して問合せを高速化することもできます。

たとえば、価格を検索して高価な品目すべてを取得するには、OCTのPrice列に対して索引を作成します。次のEXPLAIN PLANは、価格索引を使用して品目のリストを取得し、表purchaseorderと結合してPONum値を取得します。

CREATE INDEX price_index ON item_nested ("Price");

Index created.

EXPLAIN PLAN FOR
  SELECT extractValue(OBJECT_VALUE, '/PurchaseOrder/PONum') AS ponum,
         extractValue(value(it), '/Item/Part') AS part,
         extractValue(value(it), '/Item/Price') AS price
    FROM  purchaseorder,
          table(XMLSequence(extract(OBJECT_VALUE, '/PurchaseOrder/Item'))) it
    WHERE extractValue(value(it), '/Item/Price') > 2000;

Explained.

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------
| Id  | Operation                     | Name             |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |
|   1 |  NESTED LOOPS                 |                  |
|   2 |   TABLE ACCESS BY INDEX ROWID | ITEM_NESTED      |
|*  3 |    INDEX RANGE SCAN           | PRICE_INDEX      |
|   4 |   TABLE ACCESS BY INDEX ROWID | PURCHASEORDER    |
|*  5 |    INDEX UNIQUE SCAN          | SYS_C002973      |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("ITEM_NESTED"."Price">2000)
   5 - access("NESTED_TABLE_ID"="SYS_ALIAS_1"."SYS_NC0001100012$")

UPDATEXMLのXPathリライト

SQL関数updateXMLで最適化を使用するには、次の条件を満たす必要があります。

  • XMLType引数が登録済のXML Schemaに基づいていること。

  • XMLType引数がUPDATE操作のターゲットにもなっていること。次に例を示します。

    UPDATE purchaseorder_table SET OBJECT_VALUE = updateXML(OBJECT_VALUE,...);
    
  • XPath引数がすべて異なっていること(重複がない)。

  • 「リライトされるXPath式」で説明されているとおり、XPath引数がリライト可能であること。

  • XML SchemaでmaxOccurs <= 1を使用してマップされた要素をターゲットとするXPath引数は、スキーマ注釈maintainDom = falseが存在する場合にのみリライトされます。

  • XPath引数が、(XML Schemaで定義されているように)デフォルト値を持つノードをターゲットにしていないこと。

  • XPath引数が位置指定述語(たとえば、foo[2]など)を持たないこと。

  • XPath引数に述語が含まれる場合、述語がコレクションより前に出現しないこと。

    たとえば、/PurchaseOrder/LineItems[@MyAtt="3"]/LineItemは、述語がLineItemコレクションよりも出現するため、リライトされません。(これは、LineItemsが属性MyAttを持つXML Schemaを想定しています。)

  • XPath式の引数がコレクションを参照している場合、そのコレクションが、個別のOrdered Collection Tableとして格納されているか、または表外(REF記憶域)に格納されていること(つまり表内に格納されていないこと)。

  • XPath引数がコレクションを参照している場合、そのコレクションがスカラー(maxOccurs > 1であるsimpleType)でないこと。


関連項目:

updateXML式のリライト例は、例7-2例7-3および例3-35を参照してください。

INSERTCHILDXMLおよびDELETEXMLのXPathリライト

SQL関数deleteXMLで最適化を使用するには、次の条件を満たす必要があります。

  • XMLType引数が登録済のXML Schemaに基づいていること。

  • XMLType引数がUPDATE操作のターゲットにもなっていること。次に例を示します。

    UPDATE purchaseorder_table SET OBJECT_VALUE = updateXML(OBJECT_VALUE,...);
    
  • 「リライトされるXPath式」で説明されているとおり、XPath引数がリライト可能であること。

  • XPath引数が位置指定述語(たとえば、foo[2])を持たないこと。

  • XPath引数に述語が含まれる場合、述語がコレクションより前に出現しないこと。

    たとえば、/PurchaseOrder/LineItems[@MyAtt="3"]/LineItemは、述語がLineItemコレクションよりも出現するため、リライトされません。(これは、LineItemsが属性MyAttを持つXML Schemaを想定しています。)

  • XPath引数が無制限のコレクション(maxOccurs = "unbounded"が指定された要素)をターゲットにしていること。

  • XPath引数が、XML Schemaで定義されているように、コレクションのchoiceをターゲットにしていないこと。

  • ターゲットになっているコレクションの親が、XML Schema内で注釈maintainDOM = "false"を使用して定義されていること。

  • XPath引数がコレクションを参照している場合、そのコレクションが、表外(REF記憶域)でも表内でもなく個別のOrdered Collection Tableとして格納されていること。

  • XPath引数がコレクションを参照している場合、そのコレクションがスカラー(maxOccurs > 1であるsimpleType)でないこと。



脚注の凡例

脚注1: 関数tableXMLSequenceを使用するかわりに、よりわかりやすい標準のSQL/XML関数XMLTableを使用することもできます。