まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:db2

普段は MySQL 使いの自分が IBM DB2 を使おうとして、意外とハマったのが以下に紹介する2点です。

まず1点目。MySQL ではテーブル列の属性に auto_increment という指定を付与することができます:
mysql> create table langs(
  id int primary key auto_increment,
  name varchar(256)
);

この属性が付いた列はデータ挿入時に値を指定する必要がなく、定義に従ったルールでユニークな値を勝手に挿入してくれる便利な属性です(赤字はコメントです):
mysql> insert into langs( name ) values( 'Java' );  nameだけを指定してinsert
mysql> insert into langs( name ) values( 'PHP' );
mysql> insert into langs( name ) values( 'Ruby' );

mysql> select * from langs;
+----+------+
| id | name |
+----+------+
|  2 | Java | ユニークなid値が勝手に挿入されている
| 12 | PHP  |
| 22 | Ruby |
+----+------+

これと同じことを DB2 利用時にもやりたい! のですが、DB2 では create table 時に auto_increment 属性を認識してくれません。


では DB2 で同じことをするには、create table 時にどのような指定をすればよいのでしょうか?

その答がこちらです。indentity 構文を使いますが、ちと面倒:
db2> create table langs(
  id int primary key generated always as identity (start with 1 increment by 1),
  name varchar(256)
);

これをテーブル定義時に指定しておけば insert 時にはユニークな値を自動生成してくれるので楽ちんです。



2点目。同様に、MySQL では auto_increment 指定のある列に挿入された値を知りたい、と思うことがあります:
mysql> insert into langs( name ) values( 'Python' );
↑今、インサートしたこのレコードの ID 値が何だったのかを知りたい

それは LAST_INSERT_ID() で取得できました。
mysql> select last_insert_id() from langs;

これと同じことを DB2 の identity 指定した列に対してやるにはどうすればいいでしょうか?
その答は IDENTITY_VAL_LOCAL() です:
db2> select IDENTITY_VAL_LOCAL() from langs;

MySQL と DB2 で文法の違いがありますが、とりあえずはどちらも出来るということで。 

自分が迷ったのは今のところこの位ですが、Bluemix を使うユーザーが増えると必然的(?)に SQL Database や dashDB を使う人も増えると思います。DB2 をベースにしたこれらのサービスを使う時に、今回紹介したような点で戸惑う人の助けになれば幸いです。


(参考にしたページ)
http://stackoverflow.com/questions/13466347/how-to-auto-increment-in-db2
http://stackoverflow.com/questions/3087836/db2-how-to-get-the-last-insert-id-from-a-table
 

IBM Bluemix では IoT デバイスからのセンサー情報を使ったデータフローを定義する Node-RED エディタを提供しています。

特にセンサー情報はそのデバイス機器によって内容やデータフォーマットが異なるため、その内容をデータベースに保存しようと考えた場合はいわゆる NoSQL データベースを使ってテーブルを定義することなく JSON 丸ごと保存、なんてことをやったりします。これはこれで便利ですよね。

ただ保存するまではいいのですが、保存したデータを再利用する際には NoSQL だとクエリーが使えないため、その取り出しに不便に感じることもあります。その解決策の1つとしていったん Claudant に格納したデータを dashDB に複製する、という方法もあります:
Claudant => dashDB の単方向レプリケーション

そのような方法もありますが、もうデータフォーマットがわかりきっていて、NoSQL に格納する理由が特になければ最初からセンサーデータを SQL 型のデータベースに格納してしまってもいいわけです。本エントリではそんな方法のサンプルとして、Node-RED 内で SQL Database(DB2) にセンサーデータを格納する方法を紹介します。


まず Node-RED 側の用意をします。今回はすごくシンプルな形にして、IoT デバイスからのデータを一度整形して、そのままデバッグ出力するだけ、というものです:
2015051901


この中の整形部分(上記の "f" と書かれたノード)の中身は以下のようにしています。メッセージID とペイロードの名前、そして温度情報をそれぞれ ID, MYNAME, TEMP という名前で取り出しています。DB2 側で列名は大文字であることを前提とするため、JSON 側でもここを大文字にすることが肝です:
2015051902


この状態で一度デプロイして動かしてみます。ちゃんと動きますね:
2015051903


デバッグタブの出力内容は(期待通り)このようになっています。この内容を SQL Database のテーブルに格納していきます:
2015051904


では次に Bluemix 側の(SQL Database 側の)準備をします。Bluemix 上に作成した Node-RED プロジェクトランタイムで「サービスまたは API の追加」をクリックします:
2015051905


サービスの一覧から "SQL Database" を選んで追加します:
2015051906


追加が成功するとプロジェクトランタイムの中に SQL Database サービスが表示されます。このアイコンをクリックします:
2015051907


SQL Database の説明画面が表示されます。この中の "LAUNCH" ボタンをクリックしてウェブコンソールに移動します:
2015051908


ウェブコンソールが開いたら、Node-RED からのデータを格納するテーブルを定義する必要があります。そこで "Work with Tables" をクリックします:
2015051909


テーブル作業画面の左側にあるプラスマークをクリックしてテーブルを追加します:
2015051910


画面右のテキストエリアにテーブル作成の DDL を記述します:
2015051911


今回はこのような内容にしました。テーブル名は MYTABLE です:
CREATE TABLE MYTABLE
(
  ID VARCHAR(15),
  MYNAME VARCHAR(20),
  TEMP INT
);


最後に画面下部の "Run DDL" をクリックして、MYTABLE テーブルを作成します。成功すると MYTABLE テーブルが作成され、その定義内容を確認することができます:
2015051912


改めて Node-RED 画面で SQL Database の設定を追加します。ノード一覧の中から左側だけに丸のついた "sqldb"(左右に付いているのは更新用、左側だけのが追加用)を探して、キャンバスにドラッグして追加します:
2015051913


追加した "sqldb" ノードをダブルクリックし、そのサービスとテーブル名を定義します。テーブル名は先ほど作成した "MYTABLE" を指定します:
2015051914


最後にこのようにノードをつなぎます。これでデプロイ!:
2015051915


デプロイが成功するとデバッグタブにセンサー情報が表示されます。同時に SQL Database にも同じデータが格納されているはずです:
2015051916


SQL Database のウェブコンソールに戻り、MYTABLE テーブルの "Browse Data" タブを開くと追加(INSERT)されたレコードが表示されます。センサーデータが直接 DB2 に格納できたことが確認できました:
2015051917


あとは SQL を使って適当にご自由に。










 

IBM DB2 V10.5 ではテクノロジープレビューという正式サポート前の扱いですが、NoSQL 機能が使えるようになっています。

これは MongoDB のような JSON オブジェクトストア機能であり、実際に MongoDB のコマンドラインクライアントからも利用することができます。

このテクノロジープレビュー機能を有効にして、実際に使ってみるまでの手順を紹介します。なお環境は CentOS 6(64bit) 版を前提とします。


まず IBM DB2 V10.5 を導入します。DB2 は無償版の Express-C エディションが提供されているのでそれを使います。詳しい手順はこちらのエントリを参照ください(エントリはバージョン10.1での説明ですが、2015年1月5日現在、同じ手順で最新のバージョン10.5がダウンロード&導入できます):
DB2 Express-C (10.1) を CentOS にインストール&セットアップする


併せて MongoDB を導入します。詳しい手順はこちらを参照ください(この手順では MongoDB サーバーも導入されますが、今回はクライアントのみ使います):
mongoDB を CentOS 上にインストールする


最後に DB2 の NoSQL 機能を有効化する手順の中で JRE が必要になるため、Java 実行環境を導入します:
# yum install java-1.7.0-openjdk


ここまでの準備ができたら実際に DB2 の NoSQL 機能のセットアップを行います。システム上で db2inst1 ユーザーに切り替えて、NoSQL 用のデータベース jsondb をコードセット UTF-8、テリトリー jp で作成します(異なる内容で作成する場合はコマンドの赤字部分を該当内容に合わせて変更してください):
# su - db2inst1
$ db2 create database jsondb automatic storage yes using codeset utf-8 territory jp collate using system

しばらく待つと NoSQL データベース jsondb が作成されます。プロンプトが戻ったら続けて DB2 のポートを開きます。そして DB2 を再起動(ストップ&スタート)して、この内容を反映させます:
$ db2set DB2COMM=TCPIP
$ db2 update dbm cfg using svcename 50000
$ db2stop
$ db2start

そして db2inst1 ユーザーの ~/.bashrc を開いて編集し、環境変数の設定を行います:
$ vi ~/.bashrc
  :
  :
(最後に以下を追加して保存)
export JAVA_HOME=/usr/lib/jvm/jre-1.7.0-openjdk.x86_64
export PATH=$PATH:/opt/ibm/db2/V10.5/json/bin
export CLASSPATH=$CLASSPATH:/opt/ibm/db2/V10.5/json/lib/nosqljson.jar:/opt/ibm/db2/V10.5/json/lib/mongo-2.8.0.jar:/opt/ibm/db2/V10.5/json/lib/js.jar:/opt/ibm/db2/V10.5/json/lib/db2NoSQLWireListener.jar

上記で作成した jsondb データベースは初期状態では無効になっているので、コマンドラインから有効になるよう指定します。改めて db2inst1 ユーザーでログインし(或いは上記の ~/.bashrc の変更を反映し)、以下のコマンドを実行します:
# su - db2inst1
$ cd /opt/ibm/db2/V10.5/json/bin
$ ./db2nosql.sh -user db2inst1 -hostName localhost -port 50000 -db jsondb -setup enable -password (db2inst1ユーザーのパスワード)

最後に通信リスナーを MongoDB と同じ 27017 番ポートで起動します(db2inst1 ユーザーで、/opt/ibm/db2/V10.5/json/bin ディレクトリ上で実行する必要があります):
$ cd /opt/ibm/db2/V10.5/json/bin
$ ./wplistener.sh -start -mongoPort 27017 -userid db2inst1 -password (db2inst1ユーザーのパスワード) -dbName jsondb -logPath /tmp

   :
--- The wire listener is being started ---
Starting the channel listener on port 27017

上記のように、画面に "Starting the chennel listener on port 27017" と表示されれば DB2 の NoSQL データベース機能の起動に成功しています。


最後に動作確認の意味で、この DB2 上で動いている NoSQL データベース jsondb に、MongoDB クライアントから接続してみましょう。同じシステム上の別端末を開いて、mongo コマンド(MongoDB クライアント)を実行してみます(青字はシステムからの出力結果です):
# mongo
MongoDB shell version: 2.6.6
connecting to: test
>

エラーが表示されていなければ接続できたことになります。続けて jsondb データベースに接続して、myfirstcollection コレクションに "_id" = 100 の JSON 文書を作成/更新/検索してみます:
> use jsondb (DB変更)
switched to db jsondb
> db.myfirstcollection.insert( { "_id":100, "name":"K.Kimura" } ) (文書作成)
Cannot use commands write mode, degrading to compatibility mode
WriteResult({ "nInserted" : 1 })
> db.myfirstcollection.findOne() (検索)
{ "_id" : 100, "name" : "K.Kimura" } (成功)
> db.myfirstcollection.update( { "_id":100 }, {"name":"Kei KIMURA" } ) (更新)
WriteResult({ "nMatched" : 1, "nUpserted" : 0 }) (成功)
> db.myfirstcollection.findOne() (再検索)
{ "_id" : 100, "name" : "Kei KIMURA" } (成功)
  :
  :
> quit()
#

MongoDB クライアントからの一通りのコマンドは全て成功しているようです。


mongo の基本的なコマンドに関しては全て動いているようですが、どの程度の互換性があるのか/ないのか、MongoDB のライブラリが使えるのか/使えないのか、まだちょっとわかりません。 でもこれが使えるようであれば、PHP から MongoDB ライブラリを経由して DB2 にアクセスする、といった、これまでできなかったような使い方も広がってくると思います。この機能が正式サポートされるのが楽しみです。




(参考)
http://www.ibm.com/developerworks/jp/data/library/techarticle/dm-1306nosqlforjson4/
 

統合開発環境である eclipse に、リレーショナルデータベースのデータビューワである DBViewer プラグインを導入することで、開発中のアプリケーションのデータを開発環境からも比較的簡単に参照することができるようになります。

このプラグインを導入する前提として、まず Eclipse Marketplace プラグインが必要です。メニューから Help - Eclipse Marketplace が選択できるようになっていれば導入済みなので次のステップへ。
2014100301


もし Help メニューに Eclipse Marketplace が存在しない場合は最初に同プラグインを導入する必要があります。 その場合はメニューから Help - Install New Software を選びます。ダイアログではまず Work with 欄で使っている eclipse SDK のバージョン(junoとか)を選び、その下では General Purpose Tools - Marketplace Client にチェックを入れて Next > Next > 利用規格に同意 > Install です。 しばらく待つとインストールが完了し、eclipse を再起動すると Eclipse Marketplace がメニューから選択できるようになっているはずです。
2014100302


改めて eclipse のメニューから Help - Eclipse Marketplace を選択し、Search タブの Find 欄に "DBViewer" と入力して "Go" をクリックします。DBViewer プラグインが見つかるので、Install > Next > 利用規格 > Finish でインストールします。しばらく待つとインストールが完了し、eclipse を再起動すると DBViewer プラグインの導入が完了します。
2014100303


実際に DBViewer を使ってデータを参照するには、参照先データベースに対応した JDBC ドライバが必要になります。例えば接続先データベースが MySQL であれば、以下のサイトから JDBC Connector をダウンロードして JAR ファイルを展開しておきます:
MySQL : Download Connector/J

他の(Oracle や DB2, PostgreSQL などの)データベースを利用する場合も、それぞれ対応した JDBC ドライバが必要です。これらをあらかじめ用意しておきます。


これで DBViewer を利用してデータベースを参照するための準備が整いました。では実際に DBViewer でデータベースサーバーに接続して、eclipse 環境からデータの中身を参照してみます。

eclipse のメニューから Windows - Open Perspective - Other を選択し、一覧から "DBViewer" を選択して OK をクリックします。
2014100304


すると eclipse 全体が DBViewer パースペクティブに切り替わります。この段階ではまだ何の接続先定義もしていないので何も表示されていません。
2014100305


では接続先データベーステーブルを追加してみます。DBViewer パースペクティブの左上ペインの登録ボタン(上記図の赤枠部分)をクリックして「データベース定義」ダイアログを表示します。
2014100306


「データベース定義名」欄にはデータベース参照先を表す適当な名称を入力します。また「JDBC Driver」欄には接続先の JDBC ドライバを指定する必要があります。「ファイルの追加」ボタンをクリックして、先程用意した JDBC Driver の JAR ファイルを指定して Next ボタンをクリックします。なおここで指定した JDBC Driver は、この後で同じ種類のデータベースを追加する時には「登録済み Driver から選択する」をクリックするだけで指定できるようになります。
2014100307


こんな感じのダイアログが表示されたら OK をクリックします。
2014100308


次の画面で具体的な接続情報を指定します。この例では MySQL データベースに接続するので、そのような内容担っていますが、ここは実際のドライバに合わせた指定をしてください。この例では接続文字列として jdbc:mysql://(MySQL サーバー名):3306/(データベース名) を入力して、接続ユーザー名とパスワードを指定しています。念のため「テスト接続」ボタンをクリックして、実際にこの内容で接続できることを確認し、Finish ボタンをクリックします。
2014100309


今作成した内容が DB ツリービューに追加されるはずです。この DB 名部分をダブルクリックすると接続します。
2014100310


正しく接続できるとデータベース一覧、テーブル/ビュー一覧が階層的に表示され、テーブル名をダブルクリックすると、その中身が画面右側に一覧表示されます。
2014100311


接続状態を終了(切断)するにはデータベース定義名部分を右クリックして「切断」を選択します。
2014100312






 

(追記 2015.01.05)
記事タイトルでは対象バージョンを 10.1 にしていますが、2015/01/05 現在は同じ手順でバージョン 10.5 が導入されるようです。


IBM 製リレーショナルデータベースである DB2 を CentOS に導入する手順を紹介します。
2014020100

DB2 は IBM 製のリレーショナルデータベースのサーバーおよび管理システムです。1980 年にリリースされた System 38 に組み込まれており、これが SQL を初めて採用した製品、と言われています(DB2 という単体製品としては 1983 年リリース)。リレーショナルデータベースとしての機能を持ちながら、XML DB 機能が統合されていたり、最新バージョンではビッグデータの統計処理に対応するための列ストア機能にも対応しています。

DB2 は本来有償の商用製品ですが、サポートが無いことも含めた特定の条件下であれば無料でダウンロードして利用することができます(商用利用も可)。その条件で提供されるエディションが Express-C と呼ばれています。無償版用のエディション名が与えられていますが、モジュールそのものに商用版との違いはありません。結構お得感のある製品と言えます。この詳しい条件については後述の「DB2 Express-C 10.1 for Linux クイックインストール」リンク先を参照してください。


インストール&セットアップの手順を紹介する上で最初にいくつかお断りを。まず現時点で DB2 の最新バージョンは 10.5 です。以下に Express-C 版(サポート無しの無償版)の導入手順を紹介しますが、Express-C でも 10.5 を入手すること自体は可能ですが、10.5 版のインストーラは独自のもので、よく言えば「インストーラーが最初に色々やってくれて便利」なんですが、悪く言うと「普段オープンソース製品を使っている人からすると独自すぎ&最初に色々すっ飛ばされると理解できない部分がある」のでした。というわけもあって、rpm で導入できるバージョン 10.1 を対象に紹介します。

また、IBM は公式には CentOS 上での DB2 の動作を保証していません(RHEL は対象):
DB2 Express-C 10.1 for Linux クイックインストール

私自身で試した範囲では RHEL 向けの手順をそのまま利用することで CentOS でも導入できて動作することを確認していますが、とりあえず注意が必要です。


では導入手順の紹介です。上記でも少し触れましたが DB2 は(現時点では)yum でサクっと導入できるものではありません。まずはインストールモジュールをダウンロードする必要があります。そしてその前提として IBM ID というユーザーIDが必要になります。登録自体は無料です。IBM ID を所有していない場合はダウンロード前に(誘導されて)作成することになります。

DB2 バージョン10.1の場合、"DB2 Express-C Team Blog" から直接リンクがあるのでこちらからダウンロードするのが手っ取り早いです。
http://www.db2teamblog.com/2010/11/rpm-and-deb-packages-for-db2-express-c.html

2014020101


上記サイト内の "Get RPM and DEB packages for DB2 Express-C" と書かれたリンクをたどると、DB2 バージョン 10.1 の、Linux 向けインストールパッケージ(RPM版とDEB版)が、32bit/64bit 用に用意されています。自分の環境にあったものをダウンロードしましょう。とりあえず今回は CentOS 用ということで RPM 版をダウンロードしますが、Ubuntu に導入するのであれば DEB 版を選択してください。
2014020102


ダウンロードが完了すると(RPM 64bit 版であれば) IBM-DB2-EXPC-latest.x86_64.rpm という300MB前後のファイルが見つかるはずです("lastest"バージョンではない気もするけど・・・)。これがインストーラーです。こいつを sftp などを使ってインストール対象の CentOS に転送しておきます。

で、RPM を使ってインストール・・・の前にしておくことあります。DB2 はインストール時に hostname コマンドで取得できるホスト名の IP アドレス解決ができるようになっている必要があるのでした。というわけでまずは hostname を確認と。。
# hostname
test.localhost.com (例です)
# 


このホスト名の IP アドレスが解決できるようになっていないといけないのでした。上記例であればこんな感じで確認します:
# ping test.localhost.com
ping: unknown host test.localhost.com
# 


IP アドレスの解決ができていないのであれば /etc/hosts を編集しておきましょう:
# vi /etc/hosts

XXX.XXX.XXX.XXX test.localhost.com (↑ホストのIPアドレス 127.0.0.1 でも可)


ここまでできれば RPM でインストールできます:
# rpm -ivh IBM-DB2-EXPC-latest.x86_64.rpm

正常に終了すると /opt/ibm/db2/V10.1/ 以下に IBM DB2 が導入されているはずです。


ここからが RPM 版インストーラを使った場合の仕様(?)なのですが、通常の専用インストーラを使ってインストールした場合は、インストールと同時に管理に必要な各種ユーザー/グループも作成してくれたり、インスタンスを作ったり、その中にサンプルのデータベースも作ってくれたり、その中身も初めから入れておいたりしてくれます。要はインストールが完了した段階で動作確認程度の利用まではできるようになっています。一方 RPM 版の場合はそれらを別途手動で行う必要があるのです。まあ他のオープンソース RDB を使っていると後者の方が一般的だと思うのですが、要はこの段階ではまだ DB2 というサーバーモジュールがインストールされただけで、起動させるための初期設定もできていない状態だということです。


では DB2 サーバーを起動して、データベースを1つ作成して接続するところまでの手順を以下に紹介します。

DB2 サーバーを運用する上では3つの管理ユーザー/グループを用意して、指定しておく必要があります。まずインスタンス所有者としての管理ユーザー、次にユーザー定義関数やストアドプロシージャの実行権限を持った管理ユーザー、そして DB2 管理サーバーの管理ユーザー、およびこれらの所属グループです。今回はこれらのユーザーをそれぞれ db1inst1/db2fenc1/dasusr1 、またそれぞれの所属グループを db2iadm1/db2fadm1/dasadm1 として作成することにします(通常インストーラを使った場合のデフォルト設定と同じです)。


まずは管理用のグループを作成します。以下ではグループIDに997~999を使っていますが、既存環境とバッティングする場合は適当に変えてください:
# groupadd -g 999 db2iadm1
# groupadd -g 998 db2fadm1
# groupadd -g 997 dasadm1

次に管理ユーザーを作成します。以下ではユーザーIDに1002~1004を使っていますが、これも既存環境とバッティングする場合は適当に変えてください:
# useradd -u 1004 -g db2iadm1 -m -d /home/db2inst1 db2inst1
# useradd -u 1003 -g db2fadm1 -m -d /home/db2fenc1 db2fenc1
# useradd -u 1002 -g dasadm1 -m -d /home/dasusr1 dasusr1

そしてこれらの各ユーザーのパスワードを設定しておきます:
# passwd db2inst1
# passwd db2fenc1
# passwd dasusr1

ここまでの作業でやっと DB2 のインスタンスを作成する準備ができました。インスタンスの所有者を db2inst1 に、ユーザー定義関数やストアドプロシージャの管理者を db2fenc1 に指定するには以下のコマンドを実行します:
# /opt/ibm/db2/V10.1/instance/db2icrt -u db2fenc1 db2inst1

インスタンスが出来た所で DB2 サーバーを起動してみましょう。サーバーは root ユーザーでは起動できません。インスタンスオーナーである db2inst1 ユーザーで起動することになります:
# su - db2inst1
$ db2start
SQL1063N  DB2START processing was successful.
$

では起動した DB2 インスタンスに接続します:
$ db2
(c) Copyright IBM Corporation 1993,2007
Command Line Processor for DB2 Client 10.1.1

  :
  :

For more detailed help, refer to the Online Reference Manual.

db2 => 

何はともあれ、まずはデータベースを作成しましょう。コードセットは UTF-8 で、テリトリーコードを JP に設定した testdb というデータベースを作成します:
db2 => create db testdb using codeset utf-8 territory jp
DB20000I  The CREATE DATABASE command completed successfully.
db2 =>
※ちなみにこのコマンドの完了までに長い時間がかかります。コマンド入力し終わったらコーヒー一杯くらいは飲めそう(苦笑)。裏でどんな処理がされているのか分からないのですが、ここが MySQL などと大きく違う点の1つと言えるかもしれません。。

データベースに接続するには connect コマンドを利用します:
db2 => connect to testdb

   Database Connection Information

 Database server       = DB2/LINUXX8664 10.1.1
 SQL authorization ID  = DB2INST1
 Local database alias  = TESTDB

db2 => 

動いたー! d(o^ )


(2014/05/28 追加)
最後にこのサーバーへの外部アクセスを許可するための設定(というかおまじない)を db2inst1 ユーザーで実行します:
$db2set DB2COMM=TCPIP
$db2 update dbm cfg using svcename 50000

そしてこの一行を /etc/services に追加して再起動:
db2c_db2inst1   50000/tcp

(追加ここまで)


ここから先は普通の RDB 同様に、create table なり select なり、一般的な SQL の世界になります。



 

このページのトップヘ