MAGIC + DB2 で XQuery(4)
SQL/XML
東京は桜も3分咲き程で、いよいよ春到来という感じですね。
「春眠暁を覚えず」と言われますが、まさにそのとおりで、朝起きるのが辛いこの頃です。
さて、前回まではXMLデータベースの作成手順まで説明してきました。いよいよ今回はXQueryを使った検索処理です。
XQueryとは、XMLデータベース用のクエリー言語のことを言います。SQLデータベース用のクエリー言語がSQLであるのと同様に考えると分かり易いかもしれません。
DB2 9は、XQueryをSQL言語でXMLを扱うための拡張仕様であるところの「SQL/XML標準」もサポートしており、これによってSQLからXQueryを実行することが可能です。
つまり、同じ行(レコード)上のXML型の列のデータに対しては、SQL/XML関数を使うことができ、従来のSQLデータについてはSQLでクエリー処理を行うことができます。これが他のリレーショナルデータベースやXML専用データベースと異なる大きな点です。
当然ながら、通常のカラムとXML型のカラムの両者を指定した複合的なクエリー処理を行うこともできるわけです。
MAGIC V10でDB2 9を使用する場合は、このSQL/XMLを利用します。
逆な言い方をすると、MAGICのいわゆる「SQLタイプ」のタスクで定義できるSQL文は、「SELECT文」(=SQL/XML)のみなので、この方法しかありません。例えば「FLWOR」形式を使用したxquery文等の処理ができるのかどうか試みたのですが、私が試した限りではエラーが出て使えませんでした。このあたりは、DB2のゲートウェイのバージョンアップに期待したいところです。
そう言えば、書き忘れていたのですが、データベース特性のオプションにある「開発モードでのテーブル変換」ですが、これはチェックを外しておいてください。XMLタイプのカラムがあると変換に失敗してしまうので、テーブルの定義を変更するときなどは、現状は別個に修正する必要があります。
SELECT文の実際・・・
例えば、コメントに「プログラム」 と記述されたプログラムの一覧を取得することを考えて見ましょう。コメントはプログラムにも、タスクにも、項目やフォームにもつけることが可能ですが、リポジトリ上は、「Comment」というタグの「val」属性に付きます。
プログラムやタスクではなく、例えば、あるイベントに付加されたコメントの場合はどうなるでしょうか? 答えは、「/Application/ProgramsRepository/Programs/Task/.../TaskLogic/LogicUnit/Comment」となります。
MAGIC V10では、いろいろな場所にコメントを付けられますが、いずれの場合も「Comment」という名前のタグで検索することが可能です。
どんな場所に付けられたコメントでも構わずに検索する場合は「/Application//Comment」と表すことが可能です。つまり「//」は間にどんなPATHが入ってもいいよという意味です。
SELECT文は次のようになります。
select c.DATAID from DB2ADMIN.XMLDBTEST c where
xmlexists('$i/Application[//Comment/@val[contains(.,"プログラム")]]'
passing c.DATAXML as "i")
ちょっと複雑に見えるかもしれませんが、構文はお馴染みのSELECT文「SELECT ... FROM ... WHERE ... ORDER BY ... 」です。
XMLEXISTS関数は、存在すればTrueを返すもので、WHERE句に使用することが可能です。
「//Comment」で階層下の任意のコメントを表すことはすでに書いたとおりですが、プログラムのコメントのみを対象とするなら「/ProgramsRepository/Programs/Task/Header/Comment」とします。
「[contains(.,"文字列")] 」は、「文字列」を含むという条件を意味します。
もし、上記の検索に「かつ、ルートタスクがバッチタスクのプログラム」という条件を加えるなら次のようになります。("[" と "]" の中でAND条件を加えます。)
select c.DATAID from DB2ADMIN.XMLDBTEST c where
xmlexists('$i/Application[//Comment/@val[contains(.,"プログラム")]
and /ProgramsRepository/Programs/Task/Header/TaskType/@val="B"]'
passing c.DATAXML as "i")
さて、今度は返るデータについてみてみましょう。
上の例では、該当レコードの「DATAID」カラムの一覧が返ります。
例えば、ここに「xmlquery」関数を使用することにより、該当するXMLノードの結果をXMLで返すことも可能です。例えば、次のような例です。
select c.DATAID, xmlquery('$i/Application/ProgramsRepository
/Programs/Task/Header' passing c.DATAXML as "i")
from DB2ADMIN.XMLDBTEST c where
xmlexists('$i/Application[//Comment/@val[contains(.,"プログラム")]]'
passing c.DATAXML as "i")
DATAIDに続いてカンマとxmlquery関数を使った項目が指定されています。
MAGIC V10でのコーディング
実際にV10でコーディングしてみます。
プログラムは2種類作ってみます。最初は、テスト用のプログラムです。
- プログラムの定義
「SQL/XMLサンプル1」というプログラムを追加します。(タスクタイプはオンライン) - データビューの定義
メインソースなしで、変数を3つ定義します。
- 「SQL文」
文字タイプ、書式512、代入で式「'select c.DATAID, xmlquery(''$i/Application/ProgramsRepository/Programs/Task/Header'' passing c.DATAXML as "i") from DB2ADMIN.XMLDBTEST c where xmlexists(''$i/Application[//Comment/@val[contains(.,"プログラム")]]'' passing c.DATAXML as "i")'」を定義します。 - 「出力XMLファイル」
文字タイプ、書式256、代入で式「'C:\V10HACKS.XML'」を定義します。 - 「データ有り」
論理タイプ、書式5
- 「SQL文」
- ロジックの定義
イベントテーブルに「処理実行」というユーザイベントを追加しておきます。
イベントハンドラを定義し、コールサブタスク
エラーで、'データが見つかりませんでした.'、条件は「NOT(データ有り)」 - フォームの定義
SQL文を編集できるように「複数行編集」可能なエディットコントロールを配置します。
ユーザイベント「処理実行」を実行するためのプッシュボタンを配置します。 - 子タスクの定義
ロジックでコールした子タスクを作成します。(タスクタイプは同じくオンライン) - データビューの定義(子タスク)
変数を3つ追加します。
- DATAID
文字タイプ、書式20、 - HEADER
BLOBタイプ - プログラムID
数値タイプ、書式5、代入に式「Val(Del(DATAID,1,3),'5')」

TABキーを押して表示されるダイアログに下記のものをセットします。
- データベースは「DB2XML」を選択します。
- 結果データベースは「Memory」を選択します。
- SQLコマンドには、「:1」を入力します。
- 入力パラメータには、親タスクの「SQL文」項目を指定します。
- 出力パラメータは、追加した変数のDATAIDとHEADERを定義します。
- DATAID
位置付けに変数「DATAID」を指定します。 - DATAXML
XMLデータの格納されたカラムをリンクしておきます。
- DATAID
- ロジックの定義(子タスク)
ユーザイベントを4つ(「ブラウザ(QUERY)」、「ブラウザ(DATAXML)」、「XML解読」、「タスク一覧」)追加しておきます。
タスク前処理に親タスクの変数「データ有り」を'FALSE'LOGで更新を定義します。
レコード前処理に親タスクの変数「データ有り」を'TRUE'LOGで更新を定義します。
イベント「ブラウザ(QUERY)」にアクション「Blb2File (HEADER,出力XMLファイル)」と、OSコマンド「出力XMLファイル)」を定義します。
イベント「ブラウザ(DATAXML)」にアクション「Blb2File (DATAXML,出力XMLファイル)」と、OSコマンド「出力XMLファイル)」を定義します。
イベント「XML解読」に、コールサブタスクを定義します。
イベント「タスク一覧」に、コールプログラム「タスク構造取得」を定義し、パラメータに「プログラムID」を指定します。更に、条件式「DbRecs ('5'DSOURCE,'')>0」なら、コールプログラム「タスク一覧表示」を定義します。 - フォームの定義(子タスク)
テーブルコントロールに、変数「DATAID」、「プログラムID」、「HEADER」、リンク項目「DATAXML」を配置します。更に定義したイベントを起動するためのプッシュボタンを配置します。 - 孫タスクの定義
取得したXML(HEADER)を解析する子タスクを追加します。
詳細な説明は省略しますが、データビューに定義した変数に、XMLGET関数を使用して、親タスクの変数「HEADER」に格納された情報から、プログラム名、タスクタイプ、更新日付、更新時刻などの値をそれぞれ取得し画面に表示します。
このとき、XPATHが、「/Header」で始まることに注目して下さい。
変数名 値の取得方法(代入する式の値) プログラム名 XMLGet (0,1,'/Header','Description') タスクタイプ XMLGet (0,1,'/Header/TaskType','val') 更新日付 Val(XMLGet (0,1,'/Header/LastModified','_date'),'10') 更新時刻 Val(XMLGet (0,1,'/Header/LastModified','_time'),'10')
プログラムの実行
作成したプログラムを実行してみましょう。
- プログラムの起動
起動すると、ダイアログにSQL/XMLのSELECT文が表示されます(編集も可能です)。
「SQLの実行」ボタンを押すと、DB2によるデータの検索が行われます。 - SQL/XML検索結果
画面の例では、2件のプログラムが検索されました。
DB2から返る値は、出力パラメータに指定した「DATAID」と「HEADER」ですが、プログラムのIDを判別し前回作成したタスク一覧プログラムを呼び出すことが可能です。また、BLOBに格納されたXMLデータは、いずれも「Blb2File」関数でXMLに出力することが可能です。(残念ながら、「File2Blb」関数を使って、XMLをXMLタイプのカラムに挿入することはできません。) - xmlquery関数で取得したXMLデータ
ブラウザにxmlquery関数で取得したXMLデータを表示させてみます。
指定したパス以下の部分的なXMLデータが出力されることが分かります。 - MAGICでの解析
DB2に格納されたXMLデータや、検索で取得したXMLデータは、MAGICのXML関連の関数によって任意のノードの値を取得することが可能です。BLOB項目を直接指定してXMLの値の取得が可能なので、不要なIOも発生しません。
ソース公開
例によって、今回も作成したプログラムのソースを公開しておきます。

V10HACKS_20070329.lzh