第16回 私は初心者です?「5.データベースの基本を押さえる」

16−5 データベースの基本を押さえる



イメージが掴めたところで、実際にデータベースを触ってみることにしましょう。
特に今回は、キーモードのデータベースに限って触ることとします。

まず、データベースは1つのファイルなので、ファイルが存在しなければ用意しなければなりません。
正確に言えば、データベースを使おうと思った時点でファイルが存在しなければならないという事ですから、いつデータベースを作っても間違いではありません。
つまり、これだ!という正解はない訳ですが、この辺りは、各プログラマさんそれぞれ独自の方法で処理されているかと思いますので、ひとまず「mizuno-amiは、こんな風に作っています」程度でご覧下さい。

例えば「データベースから何か読み込み」をする場合を考えてみましょう。
単なる読み込みですが、簡単に次の2通りのパターンを考えることが出来ます。

       

予めデータベースファイルを作っておいて、リソースとして埋め込んでおくということも可能ですので、考えはじめればキリがない訳ですが、とりあえず私はよく2つ目のパターンをよく使います。
もちろん、上記のフローには最低限のエラーチェックしか書かれてありませんので、もう少し実際は複雑になります。
例えば、Startupでデータベースを作るには、次のようなコードを書きます。

    
    Dim Db as Database
    Dim res as Integer
    
    res=DbOpen(Db,"MyShopDb",0)
    
    If res<>0 And res<>3 Then
        res=DbCreate(Db,"MyShopDb",0,"MySp")
    Else
        res=DbClose(Db)
    End If
    

開いてみて、開くことが出来ればデータベースファイルが存在する、なければ作る、というものですが、これをStartupに埋め込んでおけば、プログラムの主要な部分を実行するときには必ずファイルが存在する、という段取りです。

 DbOpen()などデータベースに関する関数には、ほとんどの場合、その動作結果を返す戻り値があります。私の場合、これらの戻り値をresという変数に代入していますが、この値の意味はハンドブックのDbOpen()の項目にあるエラーコードになります。
うへぇ、たくさんあるなぁ、と思うかもしれませんが、細かな処理を考えなければ「操作が無事に成功した=0」と「読み取りモードで開かれている=3」という値だけ暗記しておけば大丈夫です。
乱暴な言い方ですが、0と3以外は、何か処理が失敗したという戻り値ですから、ひとまず「成功か失敗か」を知るだけなら無駄に覚える必要はありませんからね。
更に、3については、データベースファイルを作った時に限って、読み取りモードになってしまうという不具合が発生する場合があるようなので、念のため覚えているだけで、成功すれば0、それ以外は失敗、と覚えておいても、それほど不便ではありません。

 データベースファイルを作る時だけ、ファイル名に加えて「クリエータID」を指定しなければなりません。コマンドは、DbCreate()ですね。
これは、データベースファイルが、プログラムとは別のファイルである点に起因しています。
通常、Palmの標準のランチャーから、プログラムを削除する場合、その一覧にはプログラムやライブラリなどのファイルしか表示されませんので、別ファイルであるデータベースファイルは、削除できません。
プログラマから見れば不可解かもしれませんが、使う側から見れば、こんな楽なことはありません。
そもそも、データベースファイルの存在など、使う側には関係ない事ですし、そんなものの存在をユーザー側に強要するのは不親切です。
だから、PalmOSの場合、プログラムの削除画面には表面上実行できるプログラムやライブラリしか表示されず、それを削除した時は、同じクリエータIDを持ったファイルが全て削除されるという仕組みになっています。
だから、データベースファイルもクリエータIDが必要、という訳です。
もちろん、これを利用してプログラムが削除されてもデータが消えないような仕組みを作ることも可能です。代表的なのはDOCファイルに対する、色々なDOCリーダーですね。
ただし、プログラミングをする上で、データベースファイルだけを削除したいことも多々あります。
そういう場合、Filezなどのファイラーを使う必要があります。こういうツールでは、個別にファイルを削除することが出来ますので、細かなテストなどにも役に立ちます。プログラマとしては、是非、用意しておきたいツールです。

 さて、データベースファイルを作ることができれば、あとは、よく使う「検索」「追加・修正」「削除」の3つを覚えるだけで十分でしょう。順に見ていきましょう。

「検索」というと、それだけで難しそうに思えますが、検索対象になるのがインデックスの項目しかありませんので結構単純です。
「検索」は、単純に検索することと、検索してデータを読み出すことの2つの意味を持っていますが、前者の働きをするのが「DbFind()」、後者が「DbRead()」です。
どの場合でも、操作する時に、データベースが開いていなければ操作できませんので、一緒に説明します。

    
    Dim Db as Database
    Dim res as Integer
    
    res=DbOpen(Db,"MyShopDb",0)
    
    res=DbFind(Db,"AB飯店")
    
    If res>0 Then
        Msgbox "該当する店名は見つかりません。"
    End If
    
    res=DbClose(Db)
    

1、2行目は、使用する変数の宣言です。
1行目は「データベース型」という特殊な変数です。DbOpen()以後の行を見て分かるように、1度データベースファイル名を指定して開いた後は、この変数に対して操作を行えば処理できるようになっています。毎回、データベースファイルの名前を指定しなくても済むので、便利ですね。
2行目の整数型の変数は、データベースを操作したときの戻り値を格納するためのものです。
この数行の中で、DbOpen()、DbFind()、DbClose()の3つの操作を行っていますが、1つの変数を使い回しています。とりあえず、必要な時だけ値をチェックすればよいので、ダミーとして使っているようなものですね。

DbOpen()で指定するデータベースファイル名は、大文字小文字を区別しますので注意してください。
ここで、いったん戻り値resをチェックして、キチンとデータベースが開いたかどうかをチェックしても良いでしょうが、とりあえず、プログラムの先頭でデータベースファイルの有無をチェックして、無ければ作っておくという方針ですので、ここでは特にチェックはしていません。
それに、万一、ここでデータベースが開かなければ、よっぽど大変な事態じゃないかと思いますので、余程の重要なプログラムじゃない限り、必要のないチェックは省いても大丈夫でしょう。

DbFind()は文字通り、検索する関数です。
指定したインデックスが見つかれば、データベースの定石通り「無事です」の 0を返します。
次のIf文では、DbFind()の戻り値をチェックしていますが、0以外なら見つからなかったと見なして「見つかりません」と表示しています。単純ですね。
インデックスは、先にも述べたように、数値でも文字列でも構いませんが、データベースファイル毎にどちらかに決めておく必要はあります。でなければ、正確に検索できませんし、インデックスとしての役割も果たしません。今回は、センパイ君のプログラムを意識して、店名をインデックスとしましたので、文字列での指定ということになります。

使った後、データベースは閉じておく必要があります。DbClose()で閉じておきましょう。

通常、検索したら、その中のデータを取り出したいですね。
そういう場合には、DbRead()を使います。
先ほどの場合、DbFind()でインデックスが見つからなかったらエラーメッセージを表示していましたが、見つかった場合は読み込めば良いですから、次のようなコードを考えることが出来ます。

    
    Dim strInfo as string
    
    res=DbFind(Db,"AB飯店")
    
    If res=0 Then
        res=DbRead(Db,"AB飯店",strInfo)
    Else
        strInfo="該当する店名は見つかりません。"
    End if
    
    Msgbox strInfo
    

センパイ君のプログラムでは、店の情報は単純なテキストフィールド1つでしたから、とりあえず1つだけ変数を用意してみました。
そして、DbFind()で見つかった場合は、DbRead()で変数strInfoに代入しておきますます、そうでなければ変数strInfoにエラーメッセージを代入しておきます。
そして、画面に表示すれば完成ですね。

でも、普通はこんな面倒なことはしません。
なぜなら、DbRead()でもインデックスを指定する必要があるんですが、もしそのインデックスが見つからなければエラーを返すわけです。
つまり、DbRead()はDbFind()の機能も持っているわけで、たいてい、次のようにします。

    
    Dim strInfo as string
    
    res=DbRead(Db,"AB飯店",strInfo)
    
    If res>0 Then
        strInfo="該当する店名は見つかりません。"
    End if
    
    Msgbox strInfo
    

ほら、スッキリしたでしょ?

「追加」と「修正」も1つの原則が理解できていれば、それほど迷うことはありません。
その原則とは再三登場する「インデックスは重複してはならない」ということです。
ところで追加と修正の違いとは何でしょうか?これ意外と簡単で、次のように言い換えることが出来ます。

    新しく書き加えるのが「追加」
    今あるのを書き換えるのが「修正」

そして、今まで登場した「インデックスの原則」追加と修正の違いを組み合わせると、意外にも、追加と修正は1つにまとめることができるんですね。

    
    Dim strMessage as string
    
    strInfo="独特な風味の肉汁が溢れるギョウザが特徴" + Chr(10) + "商店街北" + Chr(10) + "定休日:火曜"
    
    res=DbInsert(Db,"AB飯店",strInfo)
    
    If res=0 Then
        strMessage="店の情報を追加しました。"
    Else
        res=DbUpdate(Db,"AB飯店",strInfo)
        strMessage="店の情報を更新しました。"
    End if
    
    MsgBox strMessage
    

とりあえずDbInsert()で新規に追加してみて、エラーが出ればDbUpdate()で修正をしています。
随分といい加減に感じますが、使う側にとっては「登録」と「変更」の2つのボタンを前に悩まなくても済む訳ですから、よっぽど親切です。(もちろん、場合によっては目茶目茶不親切ですが。)

最初のDbInsert()の戻り値が 0 でないときは、既に同じインデックスのデータが存在している、と勝手に決めてつけている部分もありますが、ほとんどの場合は、これが原因じゃないかと思います。
いや、あまりにも手抜きをしている部分が多いでしょう?でも、まぁ、この程度、手を抜いても実用上問題ありませんからね(経験則)

あれよあれよという間に、検索、追加・修正、済んじゃいましたね。
残る削除は削除は簡単です。
    
    res=DbDelete(Db,"AB飯店")
    

これでAB飯店の情報は消え去ります。
(もちろん、データベースを開く必要はありますし、使い終わったら閉じて下さいね。)

思ったより、データベースは単純だと思いませんか?
もちろん、今回のセンパイ君のプログラムに即して説明したので、レコードのデータが文字列1つだけという状態なので単純に思えるわけですが、複雑になっても基本は同じです。

例えば、店の特徴と休日、営業時間を個別に管理したいなら、

    DbRead(Db,"AB飯店",strTokucho,strKyujitu,strEigyo)
    

のようにカンマでくくって3つの項目を並べるだけです。
難しいのは、どういう項目にすべきか、また、文字列にするか数値にするか、という部分であり、それは操作ではなく設計の部類に入ります。
最初のうちにデータベースをどうやって使うのかキッチリ決めておかないと、後から修正するのが面倒なのは、予想がつくかと思いますが、そういう意味では確かに「難しい」ですね。
本格的に使いこなすなら、データベース的な考え方をもう少し勉強すべきですが、配列変数の代わりに使う程度なら、使っているうちに身につく程度のものです。Palmが壊れることはないでしょうから、色々とチャレンジして下さい。

■□■□■□■□■□■□■□■□■□■□■□■□

前へ    目次へ    次へ

第16回 私は初心者です?「5.データベースの基本を押さえる」