リスト3
表2●複数年月に対応した三つのテーブル(nanstb,nqustb,nenqtb)の構造
図6●集計する年月を指定する画面
リスト4
リスト5

ポイント4
テンポラリ・テーブルで複数同時処理にも対応

 ここまでの集計処理の流れをおさらいしておきましょう。ステップ1:集計用テーブル(tottb)の全件削除,ステップ2:アンケート結果(enqtb)の集計結果を集計用テーブルに保存,ステップ3:統計計算して表示,という手順になりますね。

 実を言うと,今まで紹介してきたプログラムには問題があります。それは“集計用のテーブルを一つしか用意していない”ということです。複数のユーザーが,集計処理を同時に起動したらどうなるか考えてみましょう。例えば編集部の(ま)さんが集計処理を起動してステップ3の集計/表示をしているときに,同じく編集部の(中)さんが集計処理を開始しステップ1を実行したらどうなるでしょう?*9 集計中のtottbのレコードは全件削除されてしまいます。

 これを防ぐには,テーブルにロックをかけて,他の人に削除されないようにする方法が考えられるでしょう。しかし,連載の1回目(2003年4月号)で解説したように,ロックしたままユーザーが席を離れてしまったら,ほかのユーザーが操作できなくなってしまいます。本システムはWebアプリケーションですから,(ま)さんが出張先から「今月のアンケート結果はどうかな」とのぞいてみたくなる可能性もあるわけで,そのような場合,ロックは適切な方法とは言えません。

 ではどうすればいいか。そこで登場するのが,テンポラリ・テーブル――つまり集計用に一時的なテーブルを作ろうというアイデアです。一つしかないテーブルにロックをかけて誰かをイライラさせるよりも,ユーザーごとに異なるテンポラリ・テーブルを作って,同時に複数ユーザーが集計できるようにしたほうが便利というわけです。

 さっそくコードを見てみましょう。リスト3[拡大表示](total1.php)は,リスト2をテンポラリ・テーブルを使うように改造したPHPスクリプトです。リスト3の(1)で,create temporary table tmpttb~として,テンポラリ・テーブルを作成していますね。この部分はリスト1の(2)に該当します。temporaryというキーワードがあること,テーブル名がtottbに代わってtmpttbとなっているほかは,リスト1で使ったcreate table文と変わりありません。集計用のフィールドを二つ定義している点も同じです。

 テンポラリ・テーブルは,MySQLに接続しているユーザーごとに生成できるテーブルです。テーブル名(ここではtmpttb)を指定していますが,これはプログラムを記述するための便宜的なものに過ぎず,MySQLの内部ではユーザーごとにユニークに区別されています。(ま)さん専用のtmpttb,(中)さん専用のtmpttbという具合です。接続ユーザー別にテンポラリ・テーブルが自動的に生成されるというわけです。しかもテンポラリ・テーブルは,MySQLへの接続が切れると自動的にMySQLが削除してくれます。ポイント2で紹介したtruncateの処理が不要な点も便利ですね。

 ただし注意事項が一つ。テンポラリ・テーブルをプログラムで作成するには,そのプログラムが使用する接続ユーザー(今回のサンプルではsampuser@localhost)にテーブルの作成権限(create権限)が必要なのです。そこで,あらかじめMySQL monitorを起動して,

grant create, select, insert,
update, delete on enqdb.*
to sampuser@localhost
identified by 'tbnq0206';

というSQL文を実行しておくことを忘れないでください。

 リスト3の(1)で作成されたtmpttbは,(2)で集計結果を保存し,(3)で集合関数を使って処理しています。これらの部分はリスト2の処理とまったく同じです。リスト2でtottbとなっていた部分をtmpttbに置き換えればよいわけです。

ポイント5
集計条件を指定していよいよ集計

 「やった! これで完成?」――いえいえ,まだ終わりにはできません。Webアンケート・システムをもう少し実用的なものに拡張してみたいと思います。これまで本システムでは,一度に1カ月分のデータしか取り扱えませんでした。アンケート結果を保存するenqtbだけでなく,質問テーブルqustb,選択肢を格納するテーブルanstbも毎月作り直すという前提で設計しています。つまり集計処理といっても照会できるのは最新データだけだったわけです。

 そこで,各テーブルに年,月という情報を追加し,複数号の質問,回答(選択肢),アンケート結果を保存できるようにします(表2[拡大表示])。回答(nanstb)テーブルと質問(nqustb)テーブルには,主キー(レコードをユニークに区別するフィールド)に「年(ayearとqyear)」「月(amonthとqmonth)」のフィールドを追加。アンケート結果(nenqtb)テーブルにも「年(eyear)」「月(emonth)」を追加しました。nanstbとnqustbには質問と回答を入力するタイミングで,nenqtbにはアンケートを保存するタイミングで,それぞれコントロール(contb)テーブルから今月号の年,月を同時に編集するというシナリオです*10

 まず,何年何月号のアンケート結果を集計するかという年月を指定する画面が必要ですね(図6[拡大表示])。コードはリスト4[拡大表示]のようになります。年,月を入力して集計対象の号を指定するHTMLフォーム*11を定義しています(2)。初期値として表示する年と月はcontbから取得し,dbオブジェクトのgetRowメソッド*12を使って行を取得しています(1)。このフォームで入力した年,月をtotalym.phpに渡し,その月のアンケート結果を集計するようにするわけです。

 totalym.phpの集計処理の部分を見てみましょう(リスト5[拡大表示])。$sql_aに格納するSQL文が少し複雑に見えますね(1)。集計用のテンポラリ・テーブル(tmpttb)と回答テーブル(nanstb)のそれぞれのフィールドにwhere句で選択条件を指定していますが,くくり方のレベルが違うのでわかりにくくなっています。テンポラリ・テーブルに指定する条件(tmpttb.tqno = " .$qno;)は,現在処理中の質問への回答だけを選択するという意味です。回答テーブルには,該当月の回答(選択肢:atext)を取得するように年月を指定しています("nanstb.ayear = " .$syear ."and nanstb.amonth = " .$smonth;)。

 蓄積するレコードの量が増えてくると,抽出条件を指定してデータをあらかじめ絞り込んだうえで集計処理を行うことが重要になってきます。Webアプリケーションでの集計処理はSQL文で行うこと,テンポラリ・テーブルを使うこと,ネット上に不必要のデータを流さないように適切に抽出条件を指定できるようにすることの三つを心掛けてください。



金宏和實(かねひろ・かずみ)氏

株式会社イーザー代表取締役副社長。
富山県高岡市在住。