XMLTABLE の例証: 第 1 回 XML データをリレーショナル・フォーマットで取得する

この便利な SQL/XML 関数の力を DB2 で活用する

DB2® pureXML™ は XML データの階層ストレージ、そして SQL/XML や XQuery などの高度な XML クエリー機能を提供します。SQL/XML は、SQL に XQuery または XPath を組み込めるようにするために標準化された SQL 言語の拡張です。この拡張により、XML データとリレーショナル・データの統合処理やこの 2 つのデータ間での変換が可能になります。XMLTABLE は、SQL/XML の関数のなかでもとりわけ用途の広い関数です。この連載の第 1 回では、XMLTABLE を使って XML データをリレーショナル・フォーマットで取得する方法を説明します。繰り返しの XML 要素や欠落した XML 要素を管理する方法、そして XMLTABLE 関数で名前空間を処理する方法を学んでください。続く第 2 回では、XML のシュレッディング、大規模な文書の分割、XML データでのリレーショナル・ビューなど、一般的な XMLTABLE の使用例について説明します。

Matthias Nicola (mnicola@us.ibm.com), DB2/XML Performance, IBM Silicon Valley Laboratory

Author photo: Matthias NicolaNicola 博士は、IBM Silicon Valley Lab の XML データベース・パフォーマンスの技術リーダーです。彼の業務は、XQuery、SQL/XML、また DB2 ネイティブの XML 機能を含め、DB2 での XML パフォーマンスのあらゆる側面を対象としています。Nicola 博士は DB2 XML 開発チームや XML を使用する顧客やビジネス・パートナーと緊密に業務を進めながら、XML ソリューションの設計や実装、最適化に協力しています。IBM に入社する前には、Informix Software でデータ・ウェアハウスのパフォーマンスに関する業務を行っていました。また、分散データベースや複製データベースに関する研究と業界プロジェクトにも 4 年間携わっていました。彼は、1999年にドイツの Technical University of Aachen でコンピューター・サイエンスの博士号を取得しています。


developerWorks 貢献著者レベル

Vitor Rodrigues (vrodrig@us.ibm.com), DB2 pureXML Technical Enablement, IBM

photo2Vitor Rodrigues は IBM Silicon Valley Lab のソフトウェア開発者です。コンピューター・サイエンスとシステム・エンジニアリングの専攻でポルトガルの University of Minho を卒業しています。2005年、DB2 Everyplace と DB2 9 pureXML 担当のインターンとして IBM に参加し、pureXML の DB2 9 QA チームの一員として DB2 9 の XML 機能に関する深い知識を身につけました。彼はインターンシップの後、正規社員となり、現在は DB2 9 XML Enablement チームに所属しています。


developerWorks 貢献著者レベル

2007年 8月 30日

XMLTABLE の概要

この記事を理解するには、DB2 での pureXML サポートについての知識、DB2 での XML データ・クエリーについての基本知識を持っていることが前提条件となります。この前提条件に該当しない場合は、「参考文献」セクションを参照してください。このセクションに、これらの話題を取り上げた参考記事がリストされています。

XMLTABLE は、XQuery 式を評価し、その結果をリレーショナル・テーブルとして返す SQL/XML 関数です。XQuery 式は常に XML ノードのシーケンスを返す一方、XMLTABLE はこのシーケンスをリレーショナル・フォーマットの行セットとして返します。返されるテーブルには、XML 型だけでなく、あらゆる SQL 型の列を含めることができます。

図 1. XMLTABLE の概要
XMLTABLE の概要

SQL/XML 関数の例にもれず、XMLTABLE は SQL 文に埋め込まれます。XMLTABLE 関数の評価が返す行セットでは、それぞれの列が SQL データ型となります。これはつまり、XMLTABLE はスカラー関数ではなく、テーブル関数であるということを意味します。

XMLTABLE 関数の詳細を説明するために使用する以下のサンプル・テーブルを見てください。このテーブルには 2 つの行があり、各行に 1 つの XML 文書が含まれます。

テーブル 1: サンプル・テーブルおよびサンプル・データ
create table emp (doc XML);
<dept bldg="101">
	<employee id="901">
		<name>
			<first>John</first>
			<last>Doe</last>
		</name>
		<office>344</office>
		<salary currency="USD">55000</salary>
	</employee>
	<employee id="902">
		<name>
			<first>Peter</first>
			<last>Pan</last>
		</name>
		<office>216</office>
		<phone>905-416-5004</phone>
	</employee>
</dept>
<dept bldg="114">
	<employee id="903">
		<name>
			<first>Mary</first>
			<last>Jones</last>
		</name>
		<office>415</office>
		<phone>905-403-6112</phone>
		<phone>647-504-4546</phone>
		<salary currency="USD">64000</salary>
	</employee>
</dept>

リスト 1 は、単純な XMLTABLE ステートメントの例です。

リスト 1. 単純な XMLTABLE の例
SELECT X.* 
FROM emp, 
XMLTABLE ('$d/dept/employee' passing doc as "d" 
   COLUMNS 
   empID 	INTEGER 	PATH '@id',
   firstname 	VARCHAR(20) 	PATH 'name/first',
   lastname 	VARCHAR(25) 	PATH 'name/last') AS X

このクエリーを DB2 で実行すると、以下の結果が返されます。

empID       firstname            lastname
----------- -------------------- -------------------------
        901 John                 Doe
        902 Peter                Pan
        903 Mary                 Jones

上記の仕組みを説明すると、SELECT 文の FROM 節で、XMLTABLE 関数がその操作対象の emp テーブルと併せて使用されています。これによって XMLTABLE 関数は暗黙的に emp テーブルと結合されるため、このテーブルの各列に適用されるというわけです。

XMLTABLE 関数は行を生成する XQuery 式を 1 つ含み、COLUMNS 節は列を生成する式を 1 つ以上含みます。リスト 1 で行生成式に該当するのは、XPath の $d/dept/employee です。passing 節は、変数 $d の参照先を emp テーブルの XML 列、doc に定義しています。

行生成式は XML 列の各 XML 文書に適用され、文書ごとに 1 つまたは複数の employee 要素 (サブツリー) を生成します。XMLTABLE 関数は、employee 要素ごとに 1 行の出力をします。したがって、SELECT 文の結果セットは、行を生成する XQuery 式の出力によってそのカーディナリティーが決まるということになります。

COLUMNS 節は、XML データをリレーショナル・データに変換するために使用されます。この節の各エントリーは列を列の名前と SQL データ型とともに定義します。上記の例で返される行の列は、empID、firstname、lastname の 3 つで、列のデータ型はそれぞれ Integer、Varchar(20)、Varchar(25) となります。各列の値は行生成 XQuery 式で生成された employee 要素から抽出され、該当する SQL データ型にキャストされます。例えば firstname 列の値は、各 employee 要素にパス name/first を適用して取得するといった具合です。列生成式のコンテキストは、行生成式が提供します。つまり一般的には、行生成式に列生成式を追加すれば、特定の XMLTABLE 関数が列に何を返すかが直感的にわかるというわけです。

注意する点として、COLUMNS 節のパス式は 1 行につき複数項目を返すことはできません。XMLTABLE は XML 値のシーケンスをアトミックな SQL 値に変換できないため、パス式が複数の項目のシーケンスを返すと通常は XMLTABLE が実行に失敗します。このシナリオについては後で説明します。

XMLTABLE クエリーの結果セットはあらゆる SQL テーブルと同様に扱えるので、通常の行セットやビューを使用するのと同じように、この結果セットにクエリーを実行したり、操作したりすることができます。XMLTABLE 関数へのデータ入力を指定するには、「passing column as」節を使う代わりに、db2-fn:xmlcolumn() または db2-fn:sqlquery() 関数を使用することもできます (DB2 LUW のみ)。一例として、上記のリスト 1 はリスト 2 のように記述しても同じ結果を生成します。

リスト 2. リスト 1 の別の表記
SELECT X.* 
FROM 
   XMLTABLE ('db2-fn:xmlcolumn("EMP.DOC")/dept/employee' 
      COLUMNS 
      empID		INTEGER		PATH '@id',
      firstname	VARCHAR(20)		PATH 'name/first',
      lastname	VARCHAR(25)		PATH 'name/last') AS X

欠落した要素

XML データにはどの文書にも存在しないオプション要素が含まれることがあります。例えば、サンプル・シナリオでは salary 要素は必須のデータ・フィールドではないため、テーブル 1 の従業員 Peter Pan には salary 要素がありません。このような事態に対処するのは簡単です。XMLTABLE 関数は欠落した要素に対しては単にヌル値を生成するだけなので、リスト 3 に示すとおり、salary 要素が常に存在するかのように XMLTABLE クエリーを記述することができるのです。

リスト 3. salary 列も生成するように拡張したリスト 1
SELECT X.* 
FROM emp, 
XMLTABLE ('$d/dept/employee' passing doc as "d" 
   COLUMNS 
   empID        INTEGER         PATH '@id',
   firstname    VARCHAR(20)     PATH 'name/first',
   lastname     VARCHAR(25)     PATH 'name/last',
   salary       INTEGER         PATH 'salary') AS X

このクエリーが返すのは以下の結果です。これを見るとわかるように、返されたリレーショナル・テーブルの salary 列は Peter Pan という employee 要素に対してはヌル値になります。

empID       firstname            lastname            salary
----------- -------------------- ------------------- ----------
        901 John                 Doe                 55000
        902 Peter                Pan                 -
        903 Mary                 Jones               64000

期待される要素が欠落している場合に返されるデフォルト値を定義することで、欠落した要素に例えばゼロの数値など、「ヌル」以外の値を示すこともできます。その方法を示しているのがリスト 4 です。このリストは、Peter Pan の salary 要素には「0」を返します。注意する点として、デフォルト値は列が対象とするデータ型と一致していなければなりません。つまり、「salary」は整数列にマッピングされているので、デフォルト値も整数にする必要があります。

リスト 4. 列生成式で salary のデフォルト値を使用した場合
SELECT X.* 
FROM emp, 
XMLTABLE ('$d/dept/employee' passing doc as "d" 
   COLUMNS 
   empID        INTEGER                 PATH '@id',
   firstname    VARCHAR(20)             PATH 'name/first',
   lastname     VARCHAR(25)             PATH 'name/last',
   salary       INTEGER	default 0	PATH 'salary') AS X

データのサブセットを対象とした行の生成

フィルタリング述部を基準とした従業員のサブセットだけに行を生成したいという場合もよくあります。この場合の簡単なソリューションは、XMLEXISTS 述部を指定した WHERE 節をクエリーに追加することです (これについての関連記事については、「参考文献」セクションを参照してください)。それとは別に、XMLTABLE 関数の行生成式でフィルタリング述部を使用するというソリューションもあります。例えば、ビルディング 114 の従業員に対してだけ行を生成しなければならないとします。この場合、対応する述部を上記のクエリーのいずれかに追加すると、ビルディング 114 の唯一の従業員、Mary Jones に対してのみ単一行が返されます。リスト 5 は、リスト 1 に行のフィルタリング述部を追加したものです。

リスト 5. リスト 1 に追加された行のフィルタリング述部
SELECT X.* 
FROM emp, 
XMLTABLE ('$d/dept[@bldg="114"]/employee' passing doc as "d" 
   COLUMNS 
   empID		INTEGER		PATH '@id',
   firstname	VARCHAR(20)		PATH 'name/first',
   lastname		VARCHAR(25)		PATH 'name/last',
   salary		INTEGER	default 0	PATH 'salary') AS X

各セルに含まれる複数の値の処理

前述したように、COLUMNS 節のパス式は 1 行につき複数項目を生成することはできません。しかし、テーブル 1 のサンプル文書を見ると、従業員 Mary Jones には電話番号が 2 つあります。このデータにクエリーを実行して各従業員の名前と電話番号をリストしたリレーショナル・テーブルを返すとしたら、以下のようなクエリーを作成することになるでしょう。

リスト 6. XML データのリレーショナル・テーブルへの抽出
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d" 
	COLUMNS 
	first VARCHAR(25) PATH  'name/first',
	last  VARCHAR(25) PATH  'name/last',
	phone VARCHAR(12) PATH  'phone' ) AS X

この記事で使用しているサンプル文書の場合、上記のクエリーは失敗し、以下のエラー・メッセージが生成されます。

SQL16003N An expression of data type "( item(), item()+ )" cannot be used when the data type "VARCHAR_12" is expected in the context.

このメッセージは、クエリーが複数の項目が含まれる XML シーケンスを単一の Varchar (可変文字列) 値にキャストしようとしていることを示します。データ型「(item(), item()+)」という値は、その後にさらに 1 つまたは複数の項目が続くことを意味します。簡単に言えば、この値は複数の項目を持つシーケンスであるということです。このようになってしまう理由は、パス式「phone」は従業員 Mary Jones に対して 2 つの phone 要素を返すからです。

この記事では、このエラーを受け取らないようにするための方法を説明します。その方法には以下の 5 とおりがあります。

上記のオプションはそれぞれに利点があるので、どのオプションを使用するかは必要に合わせて決められます。

複数の要素のうちから 1 つの要素だけを返す

この問題の対処法の 1 つは、複数の電話番号のなかから 1 つの電話番号だけを返すことです。必要としているのが従業員ごとの要約情報である場合、電話番号が 1 つわかれば十分なはずです。phone 要素のオカレンスを 1 つだけ返すには、phone 列の XPath 式に位置述部を使用します (リスト 7 を参照)。

リスト 7. 従業員ごとに phone 要素の最初のオカレンスを返す場合
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d" 
	COLUMNS 
	first VARCHAR(25) PATH 'name/first',
	last  VARCHAR(25) PATH 'name/last',
	phone VARCHAR(12) PATH 'phone[1]'
) AS X

XPath 内の大括弧 [] は、述部を指定するためのものです。従業員の最初の phone 要素を取得するには、位置述部を [1] または [fn:position()=1] とします。前者の表記、[1] は後者の省略バージョンです。リスト 7 が返す結果セットは以下のようになります。

first                     last                      phone
------------------------- ------------------------- ------------
John                      Doe                       -
Peter                     Pan                       905-416-5004
Mary                      Jones                     905-403-6112

  3 record(s) selected.

複数の値からなるリストを単一の Varchar で返す

すべての電話番号を返す必要がある場合は、電話番号を 1 つの列にまとめてリストすることができます。VARCHAR(12) では複数の電話番号には小さすぎるため、返される列の SQL 型は変更しなければなりません。そのため、ここでは VARCHAR(100) を使用します。これにより、コンマで区切られた複数の電話番号を生成できます (リスト 8 を参照)。

リスト 8. 各従業員のすべての電話番号をリストする場合
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d" 
	COLUMNS 
	first VARCHAR(25)  PATH  'name/first',
	last  VARCHAR(25)  PATH  'name/last',
	phone VARCHAR(100) PATH  'fn:string-join(phone/text(),",")'
) AS X

このクエリーがサンプル・データに対して返す結果は以下のとおりです。

first        last           phone
------------ -------------- -------------------------
John         Doe
Peter        Pan            905-416-5004
Mary         Jones          905-403-6112,647-504-4546

  3 record(s) selected.

従業員 Mary Jones の phone 列には 2 つの電話番号がリストされます。この 2 つの値をリンクする fn:string-join 関数にはパラメーターとして、ストリング値のシーケンスと区切り文字の 2 つが必要です。この例では、phone 要素のテキスト・ノードのシーケンスと文字「,」がこの 2 つのパラメーターに該当します。

複数の電話番号からなるリストを XML 型として返す

従業員 1 人に対して複数の電話番号を返す方法としては、phone 要素の XML シーケンスを返すという方法もあります (リスト 9 を参照)。この方法では、生成される phone 列を XML 型にして、XPath 式の結果を XML 値で返せるようにしなければなりません。この値は、アトミックな値か、またはシーケンスとなります。

リスト 9. すべての phone 要素を XML シーケンスとして返す場合
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d" 
	COLUMNS 
	first   VARCHAR(5)      PATH  'name/first',
	last    VARCHAR(5)      PATH  'name/last',
	phone   XML             PATH  'phone'
) AS X

上記のクエリーは従業員ごとに 1 行返し、その行の XML 列、phone にはその従業員の電話番号が XML シーケンスでリストされることになります。

first last  phone
----- ----- --------------------------------------------------------
John  Doe   -
Peter Pan   <phone>905-416-5004</phone>
Mary  Jones <phone>905-403-6112</phone><phone>647-504-4546</phone>
  3 record(s) selected.

Mary Jones の phone 列に返された XML 値は整形式 XML 文書ではありません。この値には単一のルート要素がないためです。この値は DB2 で処理できるものの、アプリケーションで XML 列に挿入したり、XML パーサーで構文解析したりすることはできません。整形式 XML 文書を生成しなければならない場合、例えば COLUMNS 節のパス式を「<phones>{phone}</phones> 」に変更するなどして、phone 要素のシーケンスを新しいルート要素でラップするという手を使えます。

複数の phone 列を返す

複数の電話番号を単一の Varchar または XML 値に結合するには、アプリケーションに個別の番号を使用するためのコードを追加する必要が生じてきます。各電話番号を個別の Varchar 値として返す方がよい場合は、一定数の phone 列を生成することで対応できます。リスト 10 は、位置述部を使用して 2 つの列に電話番号を返します。

リスト 10. 複数の phone 列を返す場合
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee' passing doc as "d" 
	COLUMNS 
	first  VARCHAR(25) PATH  'name/first',
	last   VARCHAR(25) PATH  'name/last',
	phone  VARCHAR(12) PATH  'phone[1]',
	phone2 VARCHAR(12) PATH  'phone[2]'
) AS X

リスト 10 のクエリーが出力する結果は以下のとおりです。

first            last            phone        phone2
---------------- --------------- ------------ ------------
John             Doe              -            -         
Peter            Pan             905-416-5004  -         
Mary             Jones           905-403-6112 647-504-4546

  3 record(s) selected.

この方法で明らかな欠点は、可変の項目数が一定の列数にマッピングされていることです。従業員が予想より多くの電話番号を持っている場合もあれば、予想の数より少ないために電話番号がヌル値になってしまうことも考えられます。しかし、すべての従業員の会社の電話と携帯電話がそれぞれ 1 つしかなければ、それぞれに対応する名前を持つ 2 つの列を生成すると非常に便利です。

電話番号ごとに 1 行返す

XMLTABLE では、電話番号を個別の列に返す代わりに個別の行で返すことも可能です。この場合、従業員ごとに 1 行返すのではなく、電話番号ごとに 1 行返すようにしてください。こうすると、名前 (first name) と苗字 (last name) の列に情報が繰り返される場合も出てきます。電話番号ごとにリレーショナル行が生成されるように XMLTABLE 関数の行生成 XPath 式を変更すると、リスト 11 のようになります。

リスト 11. 電話番号ごとに 1 行を生成する場合
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee/phone' passing doc as "d" 
	COLUMNS 
	first VARCHAR(5)  PATH  '../name/first',
	last  VARCHAR(5)  PATH  '../name/last',
	phone VARCHAR(12) PATH  '.'
) AS X

これまでのクエリーとは対照的に、リスト 11 は行生成式と列生成式の両方で異なる XPath を使用しています。今回のコンテキストはemployee 要素ではなく phone 要素なので、COLUMNS 節の XPath 式もそれに応じて変更されています。名前 (first name) と苗字 (last name) のパスが親ステップで始まっているのは、name が phone の兄弟であるためです。このクエリーの結果では、従業員 Mary Jones のリレーショナル行が 2 行となり、それぞれの行にこの従業員の電話番号のいずれかがリストされることになります。

first last  phone
----- ----- ------------
Peter Pan   905-416-5004
Mary  Jones 905-403-6112
Mary  Jones 647-504-4546

  3 record(s) selected.

存在しないパス

リスト 11 で従業員 John Doe の行が返されなかったことに疑問を持っている方もいるかもしれません。リスト 11 の行生成式は文書内のすべての phone 要素に対して繰り返されますが、従業員 John Doe には phone 要素はありません。そのため、John Doe に対応する employee 要素が処理されないのです。これに気付かないと、不完全な従業員リストを作成してしまうことになります。

こうした事態を避けるには、従業員に phone 要素がないとしても、すべての従業員に対して行を生成する必要があります。考えられるソリューションは、phone 要素がない場合には常に name 要素 (phone の兄弟) の行を生成することです。「(phone, .[fn:not(phone)]/name)」のように式をコンマで区切ったリストを使うと、両方の式が 1 つのシーケンスに結合されます。ただし、2 つの式のいずれかは常に空の結果を生成します。従業員に 1 つまたは複数の phone 要素がある場合は、そのすべての phone 要素が生成され、name 要素は文書に phone 要素がない場合にしか返されないからです。fn:not 関数が、名前と電話番号の両方を持つ従業員に対して行が重複しないようにします。リスト 12 を見てください。

リスト 12. 電話番号または名前いずれかの行を生成する方法
SELECT X.* FROM emp ,
XMLTABLE ('$d/dept/employee/(phone,.[fn:not(phone)]/name)' passing doc as "d" 
	COLUMNS 
	first VARCHAR(5)  PATH  '../name/first',
	last  VARCHAR(5)  PATH  '../name/last',
	phone VARCHAR(12) PATH  '.[../phone]'
) AS X

リスト 12 は phone 要素の行を生成するだけでなく、phone 要素が存在しなければ name 要素に対して行を生成します。従業員が複数の電話番号を持っている場合、このクエリーは電話番号ごとに行を返します。従業員に電話番号がない場合には、その従業員に対して電話番号の情報が含まれない行を 1 つだけ返します。

first last  phone
----- ----- ------------
John  Doe   -
Peter Pan   905-416-5004
Mary  Jones 905-403-6112
Mary  Jones 647-504-4546

  4 record(s) selected.

名前空間を使用した XMLTABLE

XML 名前空間は、XML 文書の要素と属性の名前を固有にするための W3C XML 標準です。XML 文書には、名前は同じでもボキャブラリーが異なる要素や属性が含まれることがあります。それぞれのボキャブラリーに名前空間を指定することで、同一の要素名または属性名のそれぞれが明確に区別されるようになります。SQL/XML、XQuery、XML 索引、そして XML スキーマ処理など、DB2 9 のすべての pureXML 機能は XML 名前空間をサポートします。名前空間を使用した XML データに対するクエリーについての詳細は、「参考文献」を参照してください。

XML 文書では、xmlns という予約済み属性を使用して XML 名前空間を宣言します。この属性の値には、URI (Universal Resource Identifier) が含まれていなければなりません。ID として使用される URI は概して URL のように見えますが、既存の Web ページを指す必要はありません。名前空間宣言には、要素および属性を識別するためのプレフィックスを含めることもできます。以下は、プレフィックスを使用した場合と使用しない場合の名前空間宣言の例です。

xmlns:ibm = "http://www.ibm.com/xmltable/"

xmlns = "http://www.ibm.com/xmltable/"

XMLTABLE での名前空間の使用方法を説明するため、以下のサンプル文書をテーブル 1 に追加します。記事の冒頭でテーブル 1 に記載した文書とは異なり、この新しい文書にはプレフィックス ibm を使用した名前空間宣言が含まれています。

リスト 13. プレフィックス付きの名前空間宣言が含まれるサンプル文書
                <ibm:dept bldg="123" xmlns:ibm="http://www.ibm.com/xmltable">
	<ibm:employee id="144">
		<ibm:name>
			<ibm:first>James</ibm:first>
			<ibm:last>Bond</ibm:last>
		</ibm:name>
		<ibm:office>007</ibm:office>
		<ibm:phone>905-007-1007</ibm:phone>
		<ibm:salary currency="USD">77007</ibm:salary>
	</ibm:employee>
</ibm:dept>

リスト 1 のクエリーをもう一度実行して、出力を確かめてください。

このクエリーを DB2 で実行すると、以下の出力が生成されます。

empID       firstname            lastname
----------- -------------------- -------------------------
        901 John                 Doe
        902 Peter                Pan
        903 Mary                 Jones

ご覧のように、従業員 James Bond に関する情報は返されません。その理由は、リスト 1 は名前空間のない要素名だけを参照するからです。データベースに含まれるすべての従業員を返すには、リスト 14 のようにパス式の名前空間プレフィックスに * ワイルドカードを使用します。このワイルドカード (*) は名前空間がない場合も含め、すべての名前空間と一致するため、すべての要素が名前空間に関わらず考慮されます。

リスト 14. ワイルドカード (*) を使用してすべての名前空間と一致させる場合
SELECT X.* 
FROM emp, 
XMLTABLE ('$d/*:dept/*:employee' passing doc as "d" 
   COLUMNS 
   empID        INTEGER         PATH '*:@id',
   firstname    VARCHAR(20)     PATH '*:name/*:first',
   lastname     VARCHAR(25)     PATH '*:name/*:last') AS X

ワイルドカードを使って文書内のすべての名前空間と一致させると、以下のようにすべての従業員が返されます。

empID       firstname            lastname
----------- -------------------- -------------------------
        901 John                 Doe
        902 Peter                Pan
        903 Mary                 Jones
        144 James                Bond

  4 record(s) selected.

この特定のデータでは、属性 @id の名前空間ワイルドカードは必ずしも必要というわけではありません。@id 属性の従業員 James Bond には名前空間がないためです。属性がその要素から名前空間を継承することはなく、また、デフォルト名前空間を想定することもありません。したがって、属性名にプレフィックスがない限り、属性が名前空間に属することはないのです。

このように、名前空間とは関係なくすべての従業員を返すのに最も簡単な方法はワイルドカード式を使用することです。次に、ibm 名前空間内の従業員の情報のみを返すにはどうすればいいかと言うと、XQuery 式または XPath 式に名前空間を指定します。それには以下の 2 つの方法があります。

デフォルト名前空間を宣言する

クエリー対象のすべての要素が同じ名前空間に属している場合は、デフォルト名前空間を宣言するのが最も簡単にクエリーを作成する方法となるはずです。XQuery 式の先頭にデフォルト名前空間を宣言するだけで、参照するすべての要素と属性名がその名前空間に結び付けられます。リスト 15 に、その方法を示します。

リスト 15. デフォルト名前空間宣言を使用する場合
SELECT X.* 
FROM emp, 
XMLTABLE ('declare default element namespace "http://www.ibm.com/xmltable";
   $d/dept/employee' passing doc as "d" 
   COLUMNS 
   empID        INTEGER         PATH '@id',
   firstname    VARCHAR(20)     PATH 
      'declare default element namespace "http://www.ibm.com/xmltable"; name/first',
   lastname     VARCHAR(25)     PATH 
      'declare default element namespace "http://www.ibm.com/xmltable"; name/last') AS X

上記の名前空間宣言を使用すると、名前空間 ibm の従業員をフィルタリングすることができます。リスト 15 の出力は以下のとおりです。

EMPID       FIRSTNAME            LASTNAME
----------- -------------------- -------------------------
        144 James                Bond

  1 record(s) selected.

列生成式は行生成式の名前空間宣言を継承しないということに注意してください。1 つひとつの列生成式は別個の XQuery であるため、列生成式には独自の名前空間宣言が必要です。これらの名前空間宣言は、例えば文書に複数の名前空間が含まれている場合などはそれぞれに異なることがありますが、たいていの場合、名前空間は 1 つしかありません。その場合には、XMLTABLE 関数のすべての式に単一の名前空間を宣言すると便利です。単一の名前空間を宣言するには XMLNAMESPACES() 関数を使用します。この関数では、デフォルト名前空間や複数の名前空間プレフィックスを XMLTABLE およびその他の SQL/XML 関数内で宣言することができます。XMLNAMESPACES 関数の利点は、この関数で宣言された名前空間は XMLTABLE コンテキストのすべての式に対してグローバルであるため、すべての XQuery 式がこれらの名前空間宣言を認識することとなり、名前空間宣言を繰り返さなくても済むことです。

それでは、XMLNAMESPACES() 関数を使ってリスト 15 を書き直してみましょう。

リスト 16. XMLNAMESPACES() によるデフォルト名前空間の宣言
SELECT X.* 
FROM emp, 
XMLTABLE (XMLNAMESPACES(DEFAULT 'http://www.ibm.com/xmltable'), 
    '$d/dept/employee' passing doc as "d" 
   COLUMNS 
   empID        INTEGER         PATH '@id',
   firstname    VARCHAR(20)     PATH 'name/first',
   lastname     VARCHAR(25)     PATH 'name/last') AS X

XMLNAMESPACES() 関数が宣言するデフォルト名前空間は、行生成式だけでなく、すべての列生成式にも適用されます。このように、1 つの名前空間宣言だけで、XMLTABLE() 関数のすべての XQuery 式に対応することができます。リスト 16 の結果は、リスト 15 の場合とまったく変わりません。

名前空間プレフィックスを宣言する

文書に名前空間が 1 つしかない場合にはデフォルト名前空間が一般的なソリューションとなりますが、文書に複数の名前空間が含まれる場合には別の手段が必要です。デフォルト名前空間を使用すると、その名前空間からしか要素と属性を選択することができません。また、ワイルドカードを使用すると、すべての名前空間の要素と属性が選択されてしまいます。複数の特定の名前空間から要素と属性を選択するには、名前空間プレフィックスを使うのが最善の方法です。

XMLNAMESPACES 関数を使用するのでない限り、名前空間プレフィックスはすべての式に対して宣言しなければなりません。しかしデフォルト名前空間の場合と同じく、XMLNAMESPACES 関数を使用すれば名前空間宣言を繰り返さなくても済みます。XMLTABLE 関数内で名前空間プレフィックスを宣言する方法は、リスト 17 のとおりです。

リスト 17. XMLNAMESPACES() 関数による名前空間プレフィックスの宣言
SELECT X.* 
FROM emp, 
XMLTABLE (XMLNAMESPACES('http://www.ibm.com/xmltable' as "ibm"), 
   '$d/ibm:dept/ibm:employee' passing doc as "d" 
   COLUMNS 
   empID 	INTEGER 	PATH '@id',
   firstname 	VARCHAR(20) 	PATH 'ibm:name/ibm:first',
   lastname 	VARCHAR(25) 	PATH 'ibm:name/ibm:last') AS X

当然、リスト 17リスト 16 と同じ結果を返します。

EMPID       FIRSTNAME            LASTNAME
----------- -------------------- -------------------------
        144 James                Bond

  1 record(s) selected.

まとめ

XMLTABLE に関するこの 2 回連載の第 1 回では、XMLTABLE を使用してリレーショナル・フォーマットで XML データを取得する方法、繰り返しの XML 要素や欠落した XML 要素および存在しないパスに対処する方法、そして XMLTABLE 関数で名前空間を扱う方法について説明しました。これで、DB2 LUW および DB2/zOS の XML データに対してクエリーを実行するための強力な一連の手段を理解できたはずです。連載第 2 回では、XML のリレーショナル・テーブルへのシュレッディング、大規模な文書の分割、さらに XML データでのリレーショナル・ビューなど、一般的な XMLTABLE の使用例について説明します。


謝辞

レビュー、そして有益なコメントでこの記事に貢献してくれた Cindy Saracco 氏に感謝します。

参考文献

学ぶために

製品や技術を入手するために

  • DB2 Enterprise 9 の無料の試用版をダウンロードしてください。
  • DB2 を無料で使用するには、コミュニティー向け DB2 Express Edition の無料バージョン、DB2 Express-C をダウンロードしてください。DB2 Express Edtion と同じコア・データ機能を備えた DB2 Express-C は、アプリケーションをビルドしてデプロイするための安定した基盤になります。
  • IBM 製品の評価版をダウンロードして、DB2®、Lotus®、Rational®、Tivoli®、および WebSphere® のアプリケーション開発ツールとミドルウェア製品を使ってみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。プロフィールで選択した情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Information Management, XML
ArticleID=259636
ArticleTitle=XMLTABLE の例証: 第 1 回 XML データをリレーショナル・フォーマットで取得する
publish-date=08302007