何と そうだったのか

ここに二つのテーブルがあります そう、片方は doctor_tblsであり、今一つは role_tblsです 簡単にすれば

doctor_tblsは

doctor_tbl_id name is_male
1 saito 1
2 shigeru 1
3 hanako 0

このようにしましょう is_maleは性別であり、男性であれば、1 女性であれば 0としましょう

もう一つのテーブルは役割配置表 role_tblsで その構造は

role_tbl_id doctor_tbl_id role_kind
1 2 chair
2 2 speaker
3 1 moderator

のように例えばなります つまり、saitoさんは doctor_tbl_id = 1ですが、 role表の中の role_tbl_id = 3に配置されていますね そして役割は moderatorということになります これをSQL文で記述すれば

SELECT * FROM `doctor_tbls` INNER JOIN `role_tbls` 
ON `doctor_tbls`.`doctor_tbl_id` = `role_tbls`.`doctor_tbl_id`;

ということになります ここで良くあるように

role_tbl_id doctor_tbl_id role_kind
1 2 chair
2 2 speaker
3 1 moderator
4 1 speaker
5 1 chair

のようにsaitoさんの役割分担が三つに増えたとしましょう この時に、役割が2つの人を探す SQL文について考えみました なかなか正解には至らなかったのですが、色々調べてようやく分かりました それは

SELECT `dr_tbl_id`, count(`dr_tbl_id`) as `Frequency` FROM `role_tbls` group by `dr_tbl_id` HAVING `Frequency` = '2'

というものです ここで HAVING句を用いるのと、仮想列名 Frequencyというのを用いるのがミソなのです 素晴らしいですね

とにかく SQLというのはプログラミング言語の中でも異色のものであり、集合演算をするのです これを理解しないと無駄足を踏むことになりますね

昨日より札幌

昨日より札幌に入っています 昨日朝 札幌には雪が降りましたが、流石にこの季節 街に積もっていた雪は溶けています 昨日はあまり元気が無く、早々と寝たのですが、01:00AMには覚醒し、それからずっとプログラム書いていました

Web上のプログラムで、TRI Maniac Confenceなどの登録サイトです。相当に securityに気を使いながら書いています。いわゆる Zendや、CakePHPなどのPHP Frameworkは使用せずに、最初からコーディングしています どうもFrameworkの中のいろいろな取り決めが嫌いで、Frameworkには馴染めません もっとも、jQueryは違います、これはFrameworkというより Javascript Libraryと言うべきかも知れませんが、これは随分と使っています

あれ程なかなか転化できなかった PDO (PHP Data Object)の世界ですが、今ではすっかり馴染んで使用しています 何しろ PDOを用いれば、SQL Injection攻撃を完璧に跳ね返すことができるので、とても貴重です 今回も MySQL Databaseとの間で SQL文を用いてデータのやり取りが何回も何回もあるのですが、その全てで PDOを用いています。これは僕にしてみれば相当な進歩です

以前PDOに馴染めなかったのは、SQL文のデバッグがしづらかったからです

  print_r($pdo->errorInfo());
  exit;

とすることにより、エラーが起きているかどうかは分かるのですが、SQL文の何処にエラーがあるのか、それがなかなかわかりづらかったので敬遠していました しかし、ローカルで立ち上げたデータベースに対して phpMyAdminを用いて SQL文を発行して、デバッグする方法を思いついたので、この壁も乗り越えることができました

という訳で今は PDOを使いまくっています

phpMyBackupProによるSQL backup dataの文字化け

ついに見つけたツール phpMyBackupProは非常に優れたものです。完璧に SQLでバック・アップが可能なのです。本当に素晴らしいと思います。しかも、フリーでダウンロードできるのです。

ただ、日本語には対応していません。このため、backupしたデータの日本語が文字化けしてしまい、そのままでは使い物になりません。データベースには UTF-8の文字コードでデータが蓄積されているので、phpMyBackupProそのもののデータ読み書きを UTF-8にすれば良いわけです。少しプログラムを見ていくと、どうやら Latinという文字コードがdefaultとして設定されているのです。まあ、どうやらイギリスで開発されているプログラムなので、かの国ではそれが標準なのでしょう。しかし、日本語対応させようと思えば、SJISあるいはEUC-Jという文字コード、そして現在の流れとしては UTF-8に対応せねばなりません。

そもそも Latinという文字コードでは一文字が 1Byte = 8 bitsであらわされます。これに対して、UTF-8では基本的に 3Bytes = 24 bitsで一文字があらわされます。日本語では、文字の数が何万とあるので、情報量として3Bytes必要なのです。

phpMyBackupProで同様の悩みをかかえて、それを解決された方がおられるのでは? と探したところ、やはりありましたね。ここ(A)です

実は、もっと有望な解説も見つけました。それはここ(B)です。このサイトでは、何と日本語化した phpMyBackupProをダウンロードできるようにしていました。しかし、その versionが 2.1とあり、現在の version 2.3よりも古いのが少し気になります。

そこで、(A)を参考に、functions.inc.phpをエディタで開いて、その 636行目に以下の文を発見しました

        // select db
        @mysql_select_db($db);

ここに 2行を追加しました:

        // select db
        @mysql_select_db($db);
		$sql = "SET NAMES utf8";		// utf8に設定する
		$res= mysql_db_query($db,"$sql");

この簡単な追加により、見事に日本語データが文字化けせずにきちんと backupされ、downloadできるようになりました。もっとも、未だテスト段階ですので、このパソコンのローカルに設定した偽装インターネット環境での確認です。

そのようにしてダウンロードした SQL文を用いて、サーバー・データが破壊されても、再構築が完璧にできるか否かを検証したところ、問題がおこりました。

きちんと SQL文では日本語が文字化けせずにダウンロードできているのに、何故か SQL文を実行して再構築すると、データベース上のデータが文字化けするのです。これは変です。 SQL文を読んでもきちんと

DEFAULT CHARSET=utf8

と設定されているのです。そこで吐き出された SQL文を最初から見ると何とその最初に

# http://www.phpMyBackupPro.net

### used character set: Latin ###
set names Latin;

というのを発見しました。折角データをutf8で設定しているのに、肝心の書き込み段階で Latinに設定されているのです。これが原因でした。
それで、この部分の Latin -> utf8に変更したところ、見事に完全データ復旧ができるようになったのです。素晴らしいです。もう少しテストしてからサーバーに実際に uploadしてみます。何はともあれ、今度のサーバー障害により色々なことを学びました。失敗から多くを学び、発展させることができました。

ついに見つけたか

これまで PHP, MySQLを用いて Web上にデータベースを構築してきましたが、そのバック・アップには少し困っていました。

MySQL自体にバック・アップのためのコマンドを持っていますが、それを作動させるためには、コマンド・ラインから起動したりせねばなりません。つまり、まあだいたい LAMPでサーバーを構築していますから、L=Linux, A=Appache, M=MySQL, P=PHP or Perlなので、OSであるLinuxのシェルを直接起動できる権限を有していないとなりません。しかしながら、我々の用いているレンタル・サーバーでは当然のことながらこれは不可能です。
また、PHPより Sytem()コマンドなどで直接MySQLのコマンドを発行することもできますが、それも大概のレンタル・サーバーでは危険な命令語として、禁じられ、潰されています。
となると、最近のレンタル・サーバーには最初からインストールしてある、phpMyAdminという秀逸のツールを用い、その上でデータベースを選択し、エキスポート・コマンドによる SQL dumpを得る、それしか現実的な選択は無くなります。
もちろんこれでこれまでバック・アップしてきたのです。しかし、そこには問題があります。

  1. phpMyAdminを用いればデータベースの全てにアクセスできてしまうので、万が一操作を間違えば全てのデータベース消失という危険な事態になりかねない
  2. 従って、この操作権限を行使するためには、プログラミングについて相当の知識が無いといけない
  3. phpMyAdminの実行を自動スケジュールすることは困難である
  4. phpMyAdminの実行を自動化することも困難である

これらの問題点から 知らない人々からは「どうしてバック・アップを私たちにさせてくれないの?」 などという非難を浴びつつ、そんなこと説明するためにはどれだけたくさんの知識をあらかじめ教授せねばならないの? と、そんな非難を自分の中で噛み潰してきたのです。

次の解決法としては、PHPでデータベースにアクセスするプログラムを書き、データのみをテーブル毎にダンプして、それをバック・アップすることです。もちろんこのプログラム作成はそれ程大変な作業ではありません。しかし、問題点としては、データというものの概念の中に、データ同士の関係、という重要な意味がある、ということなのです。特に MySQLなどの SQLデータベースは、関係データベースと称されるように、個々のテーブルに蓄えられたデータの互いの関連が重要な意味を持っているのです。

このPHPによるデータ・バック・アップでは、個々のテーブルデータをダウンロードすることはできますが、関係そのものを記録することは困難です。そのためには、 SQLにより記述したデータベース構造が必要なのです。 phpMyAdminを用いれば、SQL dumpが可能ですので、個々のテーブルデータのみならず、SQLで記述したデータ構造をもダンプできるのです。従って、データベースから全てが消失してもデータベースの完全復旧が可能なのです。

先日の、サーバー・データ消失事件においても、僕がこの SQL dumpをしていたためにデータ復旧が可能だったのです。これに反して、”Where is Dr. Saito?”で用いていたデータベースでは、このバック・アップがされていなかったため、未だに復旧できていないのです。

前置きはさておいて、ついに見つけました。素晴らしいバック・アップ・ツールを しかも完全にフリーなのです。その名前は、phpMyBackupProです。試みにこれをダウンロードしてローカルにインストールしました。素晴らしい、の一言です。しかし、大きな問題が一つ、それは データの中の日本語が文字化けしているのです。

まあ、これはMySQLにアクセスする部分でUTF-8を指定するようにプログラムを書きなおせば済むでしょう。何しろ、この優れたツールは全て PHPで記述された膨大なプログラムなのです。ですから、その部分をエディタで探して、UTF-8指定を入れればいいでしょう。チャレンジしましょう。

Ajax

Ajaxを用いて NAUSICA AMI試験の監査ツールを実装しました。Ajaxの仕組みなんてすっかり忘れていたのですが、プログラム書いている内にすぐに回復しました。やはりAjaxを用いると従来の Webページからは信じられないような画面の書き換えが行われ、プログラムを書いた甲斐があります。

その骨子は三つのパートです

  1. 主要画面
    1. ここではデータベースから受け取ったデータを cssを用いて見てくれを整えて出力する
    2. さらに、データを受信するためのボタンをつける
  2. データを受け取る Javascript (Ajax)
    1. ここがAjaxの根幹です
    2. ブラウザの Document Object Model (DOM)を用いてダイナミックに画面を書き換えます
  3. 裏で動くデータ加工プログラム
    1. データベース MySQLに対して SQLを発行してデータを得ます
    2. それを一定の形に加工します
    3. 加工の仕方としては、 JSONや HTMLを用いるのが一般的ですが、 TEXTでも良いのです 今回は HTMLを用いました

    忘れないようにおいおいプログラムを書き記します

知らなかった

何とこんなことも知りませんでした 今 NAUSICA AMI試験監査用インターフェースを作成しているのですが、そこで発行する SQLで例えば 病院毎にかつ、登録日順に並び変えるという、ごく普通の操作をすることに対して これは ORDER BY句に複数指定すれば良いだろう、ということは容易に想像つきます そこで自然に

SELECT * FROM `pt_tbl` ORDER BY `hp_id` AND `registration_date`;

としたのですが、これはとんでもない結果を返します きっと、二つの項目を合成して並び替えするのです
正解は

SELECT * FROM `pt_tbl` ORDER BY `hp_id`, `registration_date`;

なのです。こんなとも知らなかったとは驚くべしでした

月別登録症例数

月別登録症例数をSQLで書きました

SELECT DATE_FORMAT(`registration_date`, '%Y/%m')
AS `MONTH`, COUNT(1) AS `月別登録数`
FROM `pt_tbl`
GROUP BY `MONTH`
ORDER BY `MONTH` DESC

当たり前と言えば当たり前ですが、GROUP BYという集合演算は何と便利なのでしょうか!!

SQLでグループ毎の要素数で並び変える

NAUSICA AMI臨床試験において、登録症例数で病院名を出力する時に、それぞれの登録数も出力し、さらには登録数で並び変える必要がありました。これに対して、

SELECT DISTINCT `hp_name` FROM `hp_tbl` 
INNER JOIN `pt_tbl`
ON `hp_tbl`.`hp_id` = `pt_tbl`.`hp_id`

このようにすれば登録病院名のみ出力されます。しかし、登録数や登録数での並び変えは困難です正解は

SELECT`hp_name`, COUNT(*) AS 登録数 FROM `hp_tbl` 
INNER JOIN `pt_tbl` ON `hp_tbl`.`hp_id` = `pt_tbl`.`hp_id`
GROUP BY `hp_name`
ORDER BY 登録数 DESC

このようにするのです。