PHP+SQLite:SELECT文の使い方

(1/1)
今回からはいよいよ、PHP を使ってSQLiteを操作していく。
なお、PHP バージョン 5 以上を対象としている。SQLite への接続と SQL 文の実行については、データベースに依存しない方式である PDO(PHP Data Objects)クラスを利用する。

データベースを検索する手順

SQLite に限らず、一般に SQL タイプのデータベースシステム(RDBMS)を操作して検索するには、次のような手順になる。
  1. DB をオープンする
  2. SQL を実行する
  3. 結果を取り出す
  4. 結果を表示する
  5. DB をクローズする
この手順は、じつはファイル操作とほとんど同じである。ファイルをオープンした後に SQL を実行する操作が加わったと考えてもらえると分かりやすいだろう。とくに SQLite の場合、DB 本体が 1 つのファイルになっているので、これらを含めた取り扱いがファイル操作に近い。

サンプル・プログラム

サンプル・プログラムは、前回、SQLiteManager で実行させたのと同じ SQL 文

SELECT * FROM chronologic WHERE name='徳川家康';


の実行を目標にしている。

では、それぞれの手順を細かく見ていくことにしよう。

解説:準備

0009: // 初期化処理 ================================================================
0010: define('INTERNAL_ENCODING', 'UTF-8');
0011: mb_internal_encoding(INTERNAL_ENCODING);
0012: mb_regex_encoding(INTERNAL_ENCODING);
0013: define('MYSELF', basename($_SERVER['SCRIPT_NAME']));
0014: define('REFERENCE', 'http://www.pahoo.org/e-soul/webtech/php07/php07-04-01.shtm');
0015: 
0016: //プログラム・タイトル
0017: define('TITLE', 'SELECT文による1レコード選択');
0018: 
0019: //リリース・フラグ(公開時にはTRUEにすること)
0020: define('FLAG_RELEASE', FALSE);
0021: 
0022: //SQLite DBファイル名
0023: define('DBFILE', './sqlitemanager/pahoodb.sqlite3');  //各自の環境に合わせて変更すること
0024: 
0025: //実行するSQL
0026: define('SQL', "SELECT * FROM chronologic WHERE name='徳川家康';");

まず、文字コードを定数 INTERNAL_ENCODING に記載する。「SQLiteManager で DB 作成」で解説したように、データベース "pahoodb.sqlite3" は UTF-8 で作ってある。
他の文字コードも利用できるのだが、PHP バージョン 5.6 で UTF-8 がデフォルトになったこともあり、データベースもそれに合わせておいた方が無難である。

各自の環境に合わせ、SQLite の DB ファイル名を定数 DBFILE に記述する。相対パスで記述する場合は、このスクリプトがある位置からの相対位置である。

実行する SQL 文は、定数 SQL に記述する。これは、前回、SQLiteManager で使ったものと同じである。

解説:PDOの紹介

PHP は、SQLite をはじめ、オープンソースの MySQLPotstgreSQL、商用RDBMS の Microsoft SQL ServerOracleIBM DB2 など、さまざまな RDBMS に対応しており、それぞれ固有の関数群が用意されている。
だが、固有の関数群を使ってしまうと、後々、RDBMS を変更した際の改造コストが大きくなってしまう。

一方、「データベースを検索する手順」で述べたように、RDBMS の操作手順というのは製品によって大きな違いはない。製品固有の命令を使わなければ、SQL 文も共通である。
そこで PHP バージョン 5 にはPDO(PHP Data Objects)クラスが用意され、RDBMS の違いに関係なく、同じプログラムで DB 操作ができるようになった。

また、PHP 5.5 では、MySQL の操作方法として、固有の関数が廃止されることがアナウンスされた。SQLite 固有の関数は引き続きサポートされるが、せっかくなので、ここでは PDO を使っていくことにする。

解説:DBへの接続

0175: // メイン・プログラム =======================================================
0176: if (! isphp5over()) {
0177:     $errmsg = 'PHP 5 以上でないと動作しません.';
0178: else {
0179:     $errmsg = '';
0180:     $pdo = NULL;
0181:     try {
0182:         $pdo = new PDO('sqlite:' . DBFILE);
0183:         $pdo->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);
0184:     } catch (PDOException $e) {
0185:         $errmsg = 'SQLite : ' . $e->getMessage();
0186:     }
0187: }

まず、ユーザー関数 isphp5over を使って、PHP 5 以上であることをチェックする。

SQLite DB ファイル DBFILE へ接続するには、PDO オブジェクトを生成する。引数は、データソース名(DSN:Data Source Name)である。

DSN は、PDO を使って様々な RDBMS に接続するための識別子である。
たとえば SQLite であれば、"sqlite:DB ファイル名" のように指定する。
MySQL なら、"mysql:host=ホスト名;dbname=DB 名" のように指定し、第②引数でユーザー名を、第3 引数でパスワードを指定する。
その他の RDBMS については、「PDO ドライバ」を参照していただきたい。

オブジェクトが生成できたら、PDO::setAttribute を使って属性を設定する。ここでは、ATTR_ERRMODE(エラーレポート)として、ERRMODE_EXCEPTION(例外を投げる)を設定する。DB 接続に失敗したら、catch でメッセージを受け取るようにしている。

解説:SQLの実行

0146:         foreach ($pdo->query($sqlas $row) {
0147: $res .=<<< EOD
0148: <tr>
0149: <td class="index">{$row['name']}</td>            <!-- カラム name -->
0150: <td class="year">{$row['birth']}</td>            <!-- カラム birth -->
0151: <td class="year">{$row['death']}</td>            <!-- カラム death -->
0152: <td class="comment">{$row['comment']}</td>        <!-- カラム comment -->
0153: </tr>
0154: 
0155: EOD;
0156:         }

SQL 文の実行は、PDO::query を利用する。

冒頭で、DB 操作はファイル操作とほとんど同じと述べたが、SELECT 文は、テキストファイルから 1行ずつデータを取り込むのに似ている。
PDO::query を使うと、関数  fgets  を使って 1行ずつ読み込むように、for 文を使ってマッチしたデータを 1 レコードずつ読み込むことができる。

PDO::query は、最初の関数コールの中で SQL 文を実行し、結果があれば PDOStatement オブジェクトとして返す。
foreach 文と組み合わせることで、PDO::query が失敗するまで繰り返せば、1 レコードずつデータを読み込むことができる。PDO::exec とは異なり、2週目からは PDOStatement オブジェクトからデータを取り出すので、パフォーマンスが低下することもない。

あとは、取り出したオブジェクトを配列 $row に入れ、それを画面表示するための HTML 文に変換するだけである。

解説:DBの解放

0191: $pdo = NULL;

DB 処理が終わったら、PDO オブジェクトNULL を代入して解放する。

サンプル・プログラム:徳川家康の生年・没年を取得

2番目のサンプル・プログラムは、徳川家康の生年・没年のみを取り出すものである。

解説:一部カラムを取り出すSQL文

0025: //実行するSQL
0026: define('SQL', "SELECT birth, death FROM chronologic WHERE name='徳川家康';");

最初の SQL 文では取り出すカラムの種類は意識していなかったが、今度は、birth, death の 2 つのカラムだけ取り出す。
2 つの SQL 文を比較してみよう。

SELECT * FROM chronologic WHERE name='徳川家康';
SELECT birth, death FROM chronologic WHERE name='徳川家康';


上がすべてのカラムを取り出す SQL 文、下が birth, death カラムだけ取り出す SQL 文である。SELECT と FROM の間の表現が違う。
SELECT の直後にアスタリスク(*)を記述すると全てのカラムを、カラム名をカンマ(,)で区切った場合には指定したカラムだけ取り出す指示になるのだ。

解説:カラムを数値で指定する

PDO::query で配列にレコードを取り出したとき、前回のようにカラム名を添字にすることもできるし、今回のように 0 ではじまる整数で指定することもできる。この場合、SELECT の直後に指定した順番――すなわち、birth, death の順に配列に格納される。

0144:         foreach ($pdo->query($sqlas $row) {
0145: $res .=<<< EOD
0146: <tr>
0147: <td class="year">{$row[0]}</td>      <!-- カラム birth -->
0148: <td class="year">{$row[1]}</td>      <!-- カラム death -->
0149: </tr>
0150: 
0151: EOD;
0152:         }

参考サイト

(この項おわり)
header