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

投稿者: : Hitoshi Fujii

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

目次

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

SQLとは

ORDER BY句

WHERE句

nacky75

ナッキー

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

 

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サーバーは稼動中」と変化したのを確認して[閉じる](×)ボタンで終了します。

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つ、フォームの右上に配置します。

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」プロパティで「…」ダイアログボタンをクリックして、近郊県名を入力します。

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)...」を選択します。「タブ順序の設定」ダイアログボックスで、コントロールの順序を、フォームの左上から順になるように変更します。

04タブ順序

図04 タブ順序

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

05タブ順序の設定

図05タブ順序の設定

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

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コンポーネントで選択するフィールドを変更すると並び順が変化するのを確認します。

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(誕生日マスクエディット)

カテゴリ名

プロパティ名

設定値

その他