ナッキーの「Turbo Delphiはじめて奮戦記」 - 第18回 アンケートプログラムでSQLに挑戦!

By: Hitoshi Fujii

Abstract: 前回のアンケートプログラムではデータベースの基本的な操作ができるようになりました。今回はリレーショナルデータベースの特徴であるSQLという問い合わせ言語を使ったデータベースの操作を学びます。

Hide image
nacky75

ナッキー

データベースを扱うにはいろいろな方法があるんですね。SQLを使うとなんだかすごいことができそうです。

 

Hide image
takahashi75

高橋先生

前回はデータベースの操作を、メソッドを使ってやってもらったね。今回はSQLを使って「抽出」と「並べ替え」の操作をしてみよう。


    アンケートプログラムの体裁を整える

データベースはコンポーネントのメソッドを使って操作したんだけど、SQLはどうやるんですか。教えて、高橋先生!

高橋先生:先に少しだけ、操作しやすいようにコンポーネントを変更しよう。

ナッキー:前回ずいぶん手を入れましたけど、まだ手を入れるんですね。

高橋先生:住所をコンボボックスにして、一覧から選べるようにしよう。性別はラジオグループにする。それから新規作成のとき、Boolean型のデータの「性別」や「ペットの有無」にチェックを入れないと、「False」ではなくてデータがないことを意味する「Null」になるんだ。初期値をセットしておこう。それから入力しやすいようにアクセラレーター文字とタブ順序を設定しよう。

ナッキー:前回の時点で完成と思っていたけれど、まだまだやることがあるんですね。


まずはInterBase サービスマネージャーを使ってInterBaseサーバーを起動します。Windows OSのスタートメニューで「Borland InterBase 7.5 Developer [instance = gds_db]」の「InterBase サービスマネージャー [instance = gds_db]」をクリックします。「ステータス(T)」欄に、「InterBaseをWindowsサービスとして起動する」にチェックが付いていないことを確認して、「InterBaseサーバーは停止中」となっていれば、[起動(S)]ボタンをクリックして起動します。「InterBaseサーバーは稼動中」と変化したのを確認して[閉じる](×)ボタンで終了します。

Hide image
01サービスマネージャー

図01 InterBase サービスマネージャー

次にプロジェクトを開きます。Turbo Delphiを起動して、画面中央の「ホームページ」で「ProfileDB.bdsproj」を選択。もし一覧に表示されていなければ、ツールバーの[プロジェクトを開く(Ctrl+F11)]ボタンをクリックします。「プロジェクトを開く」ダイアログボックスから「ProfileDB.bdsproj」を探します。

画面上部の「FormProfileDB」タブを選択して、画面をフォームデザイナに切り替えます。フォーム上に前回作ったデータが表示されていなければ、「SQLConnection1」コンポーネントを探して「データベース」カテゴリで「Connected」プロパティを「True」にします。さらに「SimpleDatasaet1」を選択して、「その他」カテゴリの「Active」プロパティを「True」にしておきます。

プロジェクトがうまく開けたら、コンポーネントを入れ替えます。入れ替えるのは「住所」と「性別」のコンポーネントです。まず、dbedtAddressコンポーネントとdbcbxMaleコンポーネントを削除します。次に、新しいコンポーネントを配置します。画面右下のツールパレットの「Data Controls」カテゴリで「TDBComboBox」を1つ、「住所」のdbedtAddressコンポーネントがあった場所に配置します。それから、「Data Controls」カテゴリの「TDBRadioGroup」を1つ、フォームの右上に配置します。

Hide image
02コンポーネントの配置

図02 コンポーネントの配置

コンポーネントが配置できたらプロパティを設定します。データとリンクさせるプロパティは、「DataSource」プロパティと「DataField」プロパティです。DBComboBox1を選択して画面左下のオブジェクトインスペクタ、プロパティページで、「データベース」カテゴリの「DataSource」に「DataSource1」を設定します。次に「データベース」カテゴリの「DataField」に、「ADDRESS」を選択します。同様にしてDBRadioGroup1の「DataSource」に「DataSource1」、「DataField」に「MALE」を設定します。ついでにNameプロパティも設定しておきます。

DBComboBox1

カテゴリ名

プロパティ名

設定値

その他

Name

dbcmbAddress

データベース

DataSource

DataSource1

データベース

DataField

ADDRESS


DBRadioGroup1

カテゴリ名

プロパティ名

設定値

その他

Name

dbrgpMale

データベース

DataSource

DataSource1

データベース

DataField

MALE


続いてdbcmbAddressコンポーネントの住所を一覧にするために「Items」プロパティを設定します。Itemsプロパティは通常のコンボボックスと同様に設定できます。「ローカライズ対象」カテゴリの「Items」プロパティで「…」ダイアログボタンをクリックして、近郊県名を入力します。

Hide image
03文字列リストの設定

図03 文字列リストの設定

dbrgpMaleコンポーネントの「Items」プロパティには、「男性」と「女性」と入力します。前回sdsProfileシンプルデータセットコンポーネントの「DisplayLabel」プロパティに「男性;女性」のように設定したので、男性の場合はTrue、女性の場合はFalseがデータベースに代入できるんですって。ついでにCaptionプロパティも設定します。

dbcmbAddress

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Items

茨城
栃木
群馬
埼玉
千葉
東京
神奈川


dbrgpMale

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

性別

ローカライズ対象

Items

男性
女性


プロパティが設定できたら、[追加(A)]ボタンをクリックしたときに初期値を代入できるようにするんだったわね。

ナッキー:初期値をセットするって、簡単にできるんですか?

高橋先生:データセットコンポーネントのイベントを使って、フィールドに初期値を入力しよう。TSimpleDataSetコンポーネントの場合は「OnNewRecord」イベントで設定する。初期値の代入は項目コンポーネントを使おう。項目コンポーネントの名前は「データセット名 + フィールド名」となっている。「性別」の場合は「sdsProfileMALE」コンポーネント、「ペットの有無」の場合は「sdsProfilePET」コンポーネントだ。どちらもBoolean型なので、「Values」プロパティで値を代入できるよ。

ナッキー:初期値を代入できるように、イベントが用意されているんですね。


初期値をセットするイベントハンドラを作ります。sdsProfileコンポーネントの「OnNewRecord」イベントでフィールドに初期値を設定します。sdsProfileコンポーネントを選択して、オブジェクトインスペクタ、イベントページで「その他」カテゴリの「OnNewRecord」イベントをダブルクリックします。

procedure TfrmProfileDB.sdsProfileNewRecord(DataSet: TDataSet);
begin
  sdsProfileMALE.Value := True;
  sdsProfilePET.Value := False;
end;

「性別」を右に移したので、調整して整えます。それからタブ順序を設定するんでしたよね?

高橋先生:タブ順を設定しよう。入力が多いとマウスよりもキーボードから操作するほうが、楽な人も多いからね。タブ順序は「Tab」キーを押したときフォーカスが次へ移動する、そのときの順番のこと。デフォルトは配置した順になっている。

ナッキー:どうやって設定するんですか?

高橋先生:タブ順序は、フォーム上でマウスの右ボタンをクリックして、ショートカットメニューの「タブ順序(O)...」を選択する。表示される「タブ順序の設定」ダイアログボックスで入力しやすい順に並べよう。パネルに乗っているコンポーネントと乗っていないコンポーネントは同時に設定できない。それぞれで設定してから、親コンポーネントのタブ順序設定をするよ。


では、タブ順序の設定をします。画面をフォームデザイナに切り替えて、パネルの上でマウスの右ボタンをクリックします。ショートカットメニューから「タブ順序(O)...」を選択します。「タブ順序の設定」ダイアログボックスで、コントロールの順序を、フォームの左上から順になるように変更します。

Hide image
04タブ順序

図04 タブ順序

マウスでドラッグするか、矢印ボタンを使って、図05のように順序を変更します。

Hide image
05タブ順序の設定

図05タブ順序の設定

できたら、保存して実行します。ツールバーの[すべて保存]ボタンをクリックします。次にツールバーの[実行]ボタンをクリックして、実行します。いくつかデータを追加してみます。少しは入力しやすくなりましたね。

Hide image
06データの更新

図06 データの更新

    SQLとは

さあ、いよいよSQLね。SQLって何の略だったっけ?SQLを使うとテーブルみたいなものができるんだったような気がするわ。教えて、高橋先生!

高橋先生:SQLは「Structured Query Language」、日本語だと「構造化問合せ言語」の略だよ。問い合わせ先はInterBaseサーバーで、問い合わせしているのはInterBaseクライアントだったね。SQLを使うと、条件を満たすレコードだけ抽出できる。ほかにレコードを追加したり、削除したりといったデータベースの操作もできるよ。SQLの文法に従って記述した文をSQL文という。SQL文でデータを扱うものを「クエリ」と呼ぶよ。

ナッキー:いろいろできるんですよね。SQL文はTurbo Delphiみたいに書けばいいんですか?

高橋先生:文法が少し違うよ。まず、SQL文の基本的な約束から紹介しよう。書き方は、基本的に命令文では大文字小文字は区別しない。テーブル名やフィールド名は、サーバーやデータベースの種類によっては区別する場合もあるので、大文字小文字を書き分けたほうが安全だね。改行は単語の途中でなければ自由に改行できる。

ナッキー:文法を覚えるの大変そうだな。

高橋先生:最初からすべてを覚えてしまうのは難しいけれど、どんな風に書くのかは用意するよ。書き写しながら、作り方をマスターしよう。まずは、現在のテーブルのようにすべての項目表示する場合のSQL文を見てみよう。

SELECT * FROM PROFILE

「SELECT」で始まるので「SELECT」文と呼ぶ。SELECT文は「抽出」をする文だ。その隣の「*」の場所は表示するフィールドを記述する。ここではすべてのフィールドを表示するので、すべてのフィールド名を記述する代わりに「*」を入力してすべてのフィールドを持ってきている。「*」は「ワイルドカード」といって特殊な文字。FROMの次はテーブル名を記述する。特に条件を入力していないと、テーブル全体を抽出することになる。試しに、sdsProfileを使ってこのSQL文を書いてみよう。「CommandType」プロパティを「ctQuery」に変更して、「CommandText」プロパティにSQL文を書くよ。

ナッキー:これで、sdsProfileが「クエリ」になるのね。


SQL文を設定してみます。フォームデザイナの画面に戻して、sdsPrifileを選択します。そしてプロパティページ、「その他」カテゴリのActiveプロパティをFalseにしておきます。「データベース」カテゴリの「DataSet」で[+]をクリックして展開します。CommandTypeプロパティを「ctQuery」にします。次にCommandTextプロパティで「…」(ダイアログボタン)をクリックして以下の文を記述します。

SELECT * FROM PROFILE

記述できたら、「その他」カテゴリのActiveプロパティをTrueに戻して、エラーが出ないか確認します。エラーが出たら、CommandTextプロパティを確認します。

    ORDER BY句

SQLを使ってみたんだけど、変化がないからなんだか実感がわかないな。

高橋先生:じゃあ、SQL文で並べ替えをやってみたらどうかな?フィールド名の一覧から1つを選ぶと、そのフィールドで並べ替えができるようにしてみよう。名前などの文字だと音読みでの並べ替えになってしまうけど、誕生日やIDなどの数値の並べ替えは小さい順になるよ。

ナッキー:へぇ、SQL文で並べ替えまでできちゃうんだ。

高橋先生:並べ替えには「ORDER BY」句を使う。文の中の小さなひとまとまりを「句」と呼んでいる。書き方は

SELECT * FROM PROFILE ORDER BY 並べ替えのキーにしたいフィールド名

フィールド名一覧はコンボボックスを使う。一覧にはフィールド名、一覧以外から選択できないように「Style」プロパティを「csDropDownList」に設定しよう。選択したフィールド名を使ってSQL文を作るよ。


では、並べ替えのコンボボックスを作ります。ツールパレット、「Standard」カテゴリの「TLabel」と「TComboBox」を選択して、「性別」ラジオグループコンポーネントの下辺りに配置します。配置できたらプロパティを設定します。TLabelはCaptionプロパティを、TComboBoxは「Name」プロパティと「Style」プロパティ、「Items」プロパティを設定します。Itemsプロパティは1つのフィールドを1行に記述します。

TLabel

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

並べ替え


TComboBox

カテゴリ名

プロパティ名

設定値

その他

Name

cmbSort

その他

Style

csDropDownList

ローカライズ対象

Items

ID
FULLNAME
ADDRESS
BIRTHDAY
MALE
PET

ローカライズ対象

Text

削除して空白にする


プロパティが設定できたら、イベントハンドラを作成します。コンボボックスの値が変更されたときのイベント「OnChange」イベントに作成します。cmbSortを選択して、イベントページ、「その他」カテゴリの「OnChange」イベントをダブルクリックします。コードでは、まず、sdsProfileコンポーネントのActiveプロパティをFalseに設定して、閉じます。

次にCommandTextプロパティにSQLを記述してから、ActiveプロパティをTrueにして開きなおします。太字部分を追加します。

procedure TfrmProfileDB.cmbSortChange(Sender: TObject);
begin
  sdsProfile.Active := False;
  sdsProfile.DataSet.CommandText :=
    'SELECT * FROM PROFILE ORDER BY ' + cmbSort.Text;
  sdsProfile.Active := True;
end;

できたら保存して実行します。ツールバーの[すべて保存]ボタンをクリックしてから、[実行]ボタンをクリックします。cmbSortコンポーネントで選択するフィールドを変更すると並び順が変化するのを確認します。

Hide image
07並べ替え

図07 並べ替え

    WHERE句

SQL文で並べ替えができちゃいました。ORDER BY句にフィールド名を入力するだけだったわ。次はどんなSQL文が出てくるかな?教えて、高橋先生!

高橋先生:次は抽出のための重要な要素、抽出条件を作ろう。条件はだいたいTurbo Delphiのif文と似ている。条件は「WHERE」で始まるよ。

ナッキー:じゃあ、もしかして「WHERE」句?

高橋先生:そうだね。WHERE句では後ろに条件文が来る。左辺にフィールド名、右辺に条件が来て間に「=」や「>」や「<>」などの関係演算子を置く。そして条件を充たしたものだけが選ばれる。

ナッキー:複数の条件が重なることもできるんですか?

高橋先生:大丈夫だよ。「AND」を使えば条件が複数あってもすべて条件をを充たしたものが選ばれてくる。条件の入力は別のフォームを作ってそこで設定しよう。エディットやコンボボックスを並べて[OK]ボタンをクリックすると抽出のSQL文を作成して実行する。以前作ったダイアログボックスでいいよ。

ナッキー:えっと、テンプレートを使って作ったフォームでしたよね。

高橋先生:今回は、入力用のメインフォームの上半分と同じような感じにしたいので、テンプレートが用意する画面とは少し違う。がんばって、新しく作ってみよう。

ナッキー:はーい。


新しいフォームを作成します。メニューバーから「ファイル(F)|新規作成(N)」サブメニューで「フォーム - Delphi for Win32(E)」をクリックします。サイズが小さいので少し広げます。高さが大体「400」くらい幅が「350」くらいでいいです。フォームのプロパティも設定しておきます。表を参考にしてプロパティを設定します。ここではフォーム名を「Form1」として説明しますが、手順によっては「Form2」や「Form3」になる場合があります。

Form1フォーム

カテゴリ名

プロパティ名

設定値

その他

Name

frmSelect

その他

Position

poScreenCenter

ローカライズ対象

Caption

検索条件

表示

BorderStyle

bsDialog


フォームができたら、コンポーネントを配置します。メインフォームの上部と似た感じにしたいのですがデータベースと関連付けるわけではないので、通常のエディットなどを使用します。フォームの上にTLabelコンポーネントを6個、TEditを2個、TComboBoxを3個、TMaskEditを1個、TButtonを2個配置します。ツールパレットの「Standard」カテゴリで「TLabel」をクリックして、フォームの左上から順に6つ配置します。名前はLabel1から設定していきますが、名前ではなくて上からの順を優先してプロパティを設定します。

Label1ラベル

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

ID


Label2ラベル

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

名前


Label3ラベル

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

住所


Label4ラベル

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

誕生日


Label5ラベル

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

性別


Label6ラベル

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

ペット


次に、入力用のコンポーネントを配置します。「ID」と「名前」の右側に、「TEdit」をひとつずつ配置します。ツールパレットの「Standard」カテゴリで「TEdit」をクリックします。「ID」ラベルの右側に1つ、「名前」ラベルの右側に1つをそれぞれ配置します。「住所」と「性別」、「ペット」の右側には「TComboBox」を配置します。編集用のメインフォームではチェックボックスや、ラジオグループを使っていましたが、チェックボックスでは選択していない状態がわかりにくく、ラジオグループではスペースが必要ということで、ここではコンボボックスにしています。「Standard」カテゴリで「TComboBox」をクリックして、「住所」ラベル、「性別」ラベル、「ペット」ラベルの右側に1つずつ配置します。「誕生日」の右には「TMaskEdit」を配置します。「Additional」カテゴリで「TMaskEdit」をクリックします。「誕生日」ラベルの右側に配置します。最後に「TButton」コンポーネントを2つ配置します。「Standard」カテゴリで「TButton」を選択して、フォームの下部に左右に並べて配置します。

配置が完了したら、プロパティを設定します。NameプロパティとTextプロパティからはじめます。表を参考にして設定します。

Edit1(IDエディット)

カテゴリ名

プロパティ名

設定値

その他

Name

edtID

ローカライズ対象

Text

削除して空にする


Edit2(名前エディット)

カテゴリ名

プロパティ名

設定値

その他

Name

edtFullName

ローカライズ対象

Text

削除して空にする


ComboBox1(住所コンボボックス)

カテゴリ名

プロパティ名

設定値

その他

Name

cmbAddress

ローカライズ対象

Text

削除して空にする


MaskEdit1(誕生日マスクエディット)

カテゴリ名

プロパティ名

設定値

その他

Name

edtBirthday


ComboBox2(性別コンボボックス)

カテゴリ名

プロパティ名

設定値

その他

Name

cmbMale

ローカライズ対象

Text

削除して空にする

その他

Style

csDropDownList


ComboBox3(ペットコンボボックス)

カテゴリ名

プロパティ名

設定値

その他

Name

cmbPet

ローカライズ対象

Text

削除して空にする

その他

Style

csDropDownList


設定できたら、そのほかのプロパティも設定します。コンボボックスの「Items」プロパティで選択項目を入力します。「cmbMale」と「cmbPet」のコンボボックスは「Style」プロパティで「csDropDownList」も設定して一覧以外から選択できないようにします。

cmbAddress(住所コンボボックス)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Items

茨城
栃木
群馬
埼玉
千葉
東京
神奈川


cmbMale(性別コンボボックス)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Items

男性
女性


cmbPet(ペットコンボボックス)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Items

飼っている
飼っていない


誕生日のマスクエディットには年と月が入るようにします。年は西暦4桁を使用します。また、マスク文字を「文字列として保存」のチェックをはずして、何も入力されていないときには「''」(長さ0の文字列)となるようにします。

edtBirthday(誕生日マスクエディット)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

EditMask

!9999/99;0;_


さらに異なる条件文を持たせるので、その説明をラベルに追加します。ツールパレットの「Standard」カテゴリで「TLabel」を選択して、名前と誕生日の右横に1つずつラベルを配置します。配置できたらCaptionプロパティを設定します。

Label7ラベル

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

がつく名前


Label8ラベル

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

月以降


Hide image
08コンポーネントの配置

図08 コンポーネントの配置

ボタンコンポーネントは「Name」プロパティと「Caption」プロパティ、「Default」プロパティ、「Cancel」プロパティを設定します。以前ダイアログボックスを作成して、「ShowModal」メソッドでこのフォームを開いたとき、戻り値としてフォームの「ModalResult」プロパティにどのボタンが押されたのかをセットすることができました。そのときは、コードで「ModalResult」プロパティの値を代入していましたが、ボタンのプロパティでもセットできます。ボタンにも「ModalResult」プロパティがあって、ボタンをクリックしたときここにセットした値が、フォームの「ModalResult」プロパティになります。

Button1(OKボタン)

カテゴリ名

プロパティ名

設定値

その他

Default

True

その他

ModalResult

mrOk

その他

Name

btnOK

ローカライズ対象

Caption

OK(&O)


Button2(Cancelボタン)

カテゴリ名

プロパティ名

設定値

その他

Cancel

True

その他

ModalResult

mrCancel

その他

Name

btnCancel

ローカライズ対象

Caption

キャンセル(&C)


これで検索条件のフォームが作成できました。保存しておきましょう。[ツールバーのすべて保存]ボタンをクリックして保存します。ユニット名は「FormSelect」にします。

Hide image
09検索条件フォーム

図09 検索条件フォーム

ここに入力した値をもとに抽出をするんですよね。いよいよ「WHERE」句の登場!教えて、高橋先生!

高橋先生:ID、住所、性別、ペットの項目に関しては、入力された値と等しいものを抽出する。たとえばIDの場合だと

SELECT * FROM PROFILE WHERE ID = 2

のようになる。これだとIDが2のものを抽出するよ。だから、「2」の部分を「edtID.Text」にして、文字列連結すればいいんだ。コードにするとどうなるかな?

ナッキー:わ、久しぶりの例題ですね。ん~。

SELECT * FROM PROFILE WHERE ID = + edtID.Text

ですね。

高橋先生:「SELECT」から「=」までは「'」(シングルコーテーション)で囲もう。もし条件が追加されたら「AND」でつなげると、複数の条件を設定できるよ。DelphiではAND条件のとき括弧でくくることになっているけれど、SQLでは必須ではないんだ。でも念のため括弧でくくろう。

ナッキー:そっか、抽出条件フォームでは複数のフィールドに関して条件を設定できるようにしていましたよね。

高橋先生:名前の項目に関しては苗字だけや、最初の一文字でも探せるようにしたい。これは「パターン検索」や「あいまい検索」とも呼ばれる方法だよ。「LIKE」という比較演算子を使って設定する。書き方は

SELECT * FROM PROFILE WHERE フィールド名 LIKE '任意の文字列%'

こんな感じ。InterBaseでは「%」の記号は何かの文字をあらわす。「'佐%'」とすると「佐竹」でも「佐藤」でも「佐野山」でも条件を充たすレコードとなる。先頭の一文字に限らず中に含まれる文字としたい場合は「'%山%'」とすると「山本」でも「中山」でも条件を充たすレコードとなる。今回は先頭の一文字としたいからedtNameコンポーネントのTextプロパティの後ろに「%」をつけよう。「%」の記号はすべてのデータベースソフトに共通の決まりではない。データベースソフトが違うと記号が異なることもあるから気をつけてね。

ナッキー:便利な記号があるんですね。これなら名前がちょっと思い出せないときでも探せます。

高橋先生:それから、誕生日に関しては年と月を入力してもらって、入力した日付以降の条件を充たすものを抽出しよう。書き方は

SELECT * FROM PROFILE WHERE (BIRTHDAY >= '1970/10/01')

月までしか入力してもらわないから末尾に「'/01'」を加えて条件にするよ。

SELECT * FROM PROFILE WHERE BIRTHDAY >= edtBirthday.Text + '/01'

ナッキー:すごくいろいろな条件が組み合わさるんですね。条件が入っていればANDでつなげることも必要だし。あ、括弧もつけるんでしたよね。

高橋先生:AND条件がないときに括弧を付けても問題にはならないから、括弧は常に付けてもいいと思うよ。変数などに「WHERE」以降の文字列をためておいて。あとで「SELECT」から「WHERE」までの文をつなげるといいね。あ、コードを記述する前にuses節に検索条件フォームを追加しておいてね。メニューから設定する方法覚えているよね。

ナッキー:[ファイル(F)|ユニットを使う(U)...]でuses節に追加するんでしたよね。でもWHERE句はちょっと難しそう。


まずは、抽出条件のフォームを表示するためのボタンをメインフォームに追加します。ついでに抽出を解除するボタンもつけておきます。

画面上部のタブで「FormProfileDB」を探してクリックします。フォームデザイナの画面でなければ切り替えておきます。ツールパレットの「Standard」カテゴリで「TButton」をクリックして、フォームの並べ替えコンボボックスの下に配置します。隣にもう1つボタンを配置します。NameプロパティとCaptionプロパティを設定します。表を参考にして設定します。

Button1(検索ボタン)

カテゴリ名

プロパティ名

設定値

その他

Name

btnSelect

ローカライズ対象

Caption

検索(&K)


Button2(検索解除ボタン)

カテゴリ名

プロパティ名

設定値

その他

Name

btnKaijo

ローカライズ対象

Caption

検索解除(&J)


ボタンができたら、さっき作ったフォームをuses節に加えます。[ファイル(F)|ユニットを使う(U)...]で表示される「ユニットの使用」ダイアログボックスで「FormSelect」を選択して[OK]ボタンをクリックします。

イベントを作ります。btnSelectコンポーネントを選択して、イベントページの「入力」カテゴリで「OnClick」を探して、ダブルクリックします。コードエディタに切り替わったら、変数を宣言します。「begin」の前にvar節を置いて、「s」という変数名をstring型で宣言します。太字部分を追加します。

procedure TfrmProfileDB.btnSelectClick(Sender: TObject);
var
  s : string;
begin

end;

次に、検索条件フォームを開いて、「ModalResult」が「mrOK」かどうかのif文を作ります。if文の中は複数文あるので「begin」と「end;」でくくっておきます。また変数sに初期値として「''」(長さ0の文字列)を代入しておきます。太字部分を追加します。

procedure TfrmProfileDB.btnSelectClick(Sender: TObject);
var
  s : string;
begin
  s := '';
  frmSelect.ShowModal;
  if frmSelect.ModalResult = mrOk then
  begin

  end;
end;

変数sに代入する値を確認します。まずIDからチェックします。もしもedtIDに値が入っていれば、sに条件文「(ID = edtID.Text)」を代入します。

if frmSelect.edtID.Text <> '' then
  s := '(ID = ' + frmSelect.edtID.Text + ')';

このような文になります。

次は名前です。名前の前にIDの条件文が入っているとき、「AND」でつなげる必要があります。この後登場する項目すべてにつける必要があります。

if s <> '' then
  s := ' AND ';

名前の条件を設定する場合に、名前を「'」(シングルコーテーション)で囲む必要があります。文字列の中に「'」を代入するときは「''」(シングルコーテーション2つ)を入れると文字列の中に記号が埋め込まれるんですって。それからパターン検索のため「'」で囲んだ中の末尾に「%」も加えます。

if frmSelect.edtFullName.Text <> '' then
begin
  if s <> '' then
    s := s + ' AND ';
  s := s + '(FULLNAME LIKE ''' + frmSelect.edtFullName.Text + '%'')';
end;

住所はレコードの内容と同じかどうか調べるだけです。

if frmSelect.cmbAddress.Text <> '' then
begin
  if s <> '' then
    s := s + ' AND ';
  s := s + '(ADDRESS = ''' + frmSelect.cmbAddress.Text + ''')';
end;

次の誕生日は末尾に「/01」を足してその日付以上かどうかを調べます。

if frmSelect.edtBirthday.Text <> '' then
begin
  if s <> '' then
    s := s + ' AND ';
  s := s + '(BIRTHDAY >= ''' + frmSelect. edtBirthday.Text + ''')';
end;

性別は男性のとき「TRUE」、女性のとき「FALSE」を代入するので、条件文は「'男性'」か「'女性'」かをそれぞれチェックします。

if frmSelect.cmbMale.Text <> '' then
begin
  if s <> '' then
    s := s + ' AND ';
  if frmSelect.cmbMale.Text = '男性' then
    s := s + '(MALE = TRUE)'
  else if frmSelect.cmbMale.Text = '女性' then
    s := s + '(MALE = FALSE)';
end;

ペットを飼っているかどうかも、性別の場合と同じように「'飼っている'」か「'飼っていない'」かをチェックします。

if frmSelect.cmbPet.Text <> '' then
begin
  if s <> '' then
    s := s + ' AND ';
  if frmSelect.cmbPet.Text = '飼っている' then
    s := s + '(PET = TRUE)'
  else if frmSelect.cmbPet.Text = '飼っていない' then
    s := s + '(PET = FALSE)';
end;

s変数に値が入ったらsdsProfileのActiveプロパティをFalseにして閉じてから、「CommandText」プロパティにSQL文を代入します。文字列「'SELECT * FROM PROFILE WHERE '」にs変数を結合するとSQL文が完成します。次にsdsProfileのActiveプロパティをTrueにして、SQL文を実行します。すべての文をつなげると以下のようになります。太字部分を記述します。

procedure TfrmProfileDB.btnSelectClick(Sender: TObject);
var
  s : string;
begin
  s := '';
  frmSelect.ShowModal;
  if frmSelect.ModalResult = mrOk then
  begin
    if frmSelect.edtID.Text <> '' then
      s := '(ID = ' + frmSelect.edtID.Text + ')';
    if frmSelect.edtFullName.Text <> '' then
    begin
      if s <> '' then
        s := s + ' AND ';
      s := s + '(FULLNAME LIKE ''' + frmSelect.edtFullName.Text + '%'')';
    end;
    if frmSelect.cmbAddress.Text <> '' then
    begin
      if s <> '' then
        s := s + ' AND ';
      s := s + '(ADDRESS = ''' + frmSelect.cmbAddress.Text + ''')';
    end;
    if frmSelect.edtBirthday.Text <> '' then
    begin
      if s <> '' then
        s := s + ' AND ';
      s := s + '(BIRTHDAY >= ''' + frmSelect. edtBirthday.Text + ''')';
    end;
    if frmSelect.cmbMale.Text <> '' then
    begin
      if s <> '' then
        s := s + ' AND ';
      if frmSelect.cmbMale.Text = '男性' then
        s := s + '(MALE = TRUE)'
      else if frmSelect.cmbMale.Text = '女性' then
        s := s + '(MALE = FALSE)';
    end;
    if frmSelect.cmbPet.Text <> '' then
    begin
      if s <> '' then
        s := s + ' AND ';
      if frmSelect.cmbPet.Text = '飼っている' then
        s := s + '(PET = TRUE)'
     else if frmSelect.cmbPet.Text = '飼っていない' then
       s := s + '(PET = FALSE)';
    end;
    sdsProfile.Active := False;
    sdsProfile.DataSet.CommandText :=
     'SELECT * FROM PROFILE WHERE ' + s;
    sdsProfile.Active := True;
  end;
end;

ふう。長かったですね。もう1つ「検索解除」ボタンも作ります。btnKaijoコンポーネントを選択して、イベントページの「入力」カテゴリで「OnClick」を探して、ダブルクリックします。コードエディタに切り替わったら、sdsProfileのCommandTextプロパティを元の状態に戻します。太字部分を追加します。

procedure TfrmProfileDB.btnKaijoClick(Sender: TObject);
begin
  sdsProfile.Active := False;
  sdsProfile.DataSet.CommandText := 'SELECT * FROM PROFILE';
  sdsProfile.Active := True;
end;

記述できたら、保存して実行してみます。ツールバーの[すべて保存] ボタンで保存して、[実行]ボタンで実行テストします。実行テストではいろいろな検索をしてみてください。検索を確かめるために、データを追加してもいいですよ。

Hide image
10完成図

図10 完成図

Hide image
11検索結果

図11 検索結果

ナッキー:WHERE句でいろいろな抽出をやってみて、SQL文で操作する感じが、少しはわかってきたみたいです。

高橋先生:いろいろできるから楽しいよ。Windows OSのスタートメニューに「Borland InterBase 7.5 Developer [instance = gds_db]」があるよね。このメニューの中に「Documentation」フォルダがあって、中に「埋め込みSQLガイド」というPDF形式のファイルがあるから参考にしてみてね。

ナッキー:あ、マニュアルだ。マニュアルって聞くとつい拒否反応が出ちゃって読むのを途中であきらめがちなんですよね。

高橋先生:全部読もうと思うから、大変な気持ちになっちゃうんだよ。興味のあるところだけ拾い読みできるようになっているから、部分的にでも読んでみたら?

ナッキー:LIKEとか見てみようかな。

高橋先生:そうそう、そんな感じでOK。PDFだから検索もできる。疑問点があったら誰かに聞く前に調べてみると実力もアップするよ。次回もデータベース操作にもっと強くなろう。


ナッキーの「Turbo Delphiはじめて奮戦記」

Prev | Next | Index


Server Response from: ETNASC03