Description
クエリ結果からの個々の行の取得
MDB2_Result_Common オブジェクトには、結果セットの行からデータを取得するための
4 つのメソッドがあります。
fetchOne()、
fetchRow()、
fetchCol() そして
fetchAll() です。
fetchRow() および fetchOne()
は、それぞれ行全体あるいは特定のカラムのフィールドを取得します。
結果ポインタは、これらのメソッドがコールされるたびに次の行に移動します。
結果セットの最後に達した場合は NULL が返されます。
fetchAll() および fetchCol()
は、結果セットのすべての行を読み込んで結果ポインタを最後まで移動します。
fetchAll() は行全体のデータを読み込みますが、
fetchCol() は特定のカラムのみを読み込みます。
エラーが発生した場合は MDB2_Error が返されます。
<?php
// まずプログラムの最初に、$mdb2 という名前の
// MDB2 オブジェクトを作成します
require_once 'MDB2.php';
$mdb2 =& MDB2::connect('pgsql://usr:pw@localhost/dbnam');
if (PEAR::isError($mdb2)) {
die($mdb2->getMessage());
}
// 何らかのデータを取得します
$res =& $mdb2->query('SELECT * FROM mytable');
// 各行のデータを順に取得し、
// 行がなくなるまで続けます
while (($row = $res->fetchRow())) {
// MDB2 のデフォルトのフェッチモードが MDB2_FETCHMODE_ORDERED であるとします
echo $row[0] . "\n";
}
// while (($one = $res->fetchOne())) {
// echo $one . "\n";
// }
?>
取得した行の形式
クエリの結果の行から取得したデータは、
数値添字配列 (カラム番号をキーとする)、
連想配列 (カラム名をキーとする) あるいは
オブジェクト (カラム名をプロパティとする)
の三種類のうちのいずれかの形式となります。
MDB2_FETCHMODE_ORDERED (デフォルト)
Array
(
[0] => 28
[1] => hi
)
MDB2_FETCHMODE_ASSOC
Array
(
[a] => 28
[b] => hi
)
MDB2_FETCHMODE_OBJECT
stdClass Object
(
[a] => 28
[b] => hi
)
注意: クエリの中に同名のカラムが複数含まれており
(例えば、同じ名前のカラムがある複数テーブルを JOIN
した場合など)、かつフェッチモードが
MDB2_FETCHMODE_ASSOC あるいは
MDB2_FETCHMODE_OBJECT
の場合は、その名前を指定すると
最後に登場したカラムの値が返されます。
この問題を解決するとりあえずの方法としては、次のふたつがあります。
-
クエリの中で、例えば
People.Name AS PersonName
のようにエイリアスを使用する。
-
フェッチモードを MDB2_FETCHMODE_ORDERED
に変更する。
豆知識: この問題が発生する場合、
データベースのスキーマに問題があることが多いです。
例えば同じデータが二重に管理されていたり、
異なる内容のデータに同じ名前をつけてしまっていたり
といったことが考えられます。
書式設定の方法
fetch メソッドをコールするたびにフェッチモードを設定することもできますし、
MDB2 インスタンス全体のデフォルトのフェッチモードを設定することもできます。
デフォルトのフェッチモードを設定するには
setFetchMode()
メソッドを使用します。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$res =& $mdb2->query('SELECT * FROM users');
while ($row = $res->fetchRow(MDB2_FETCHMODE_ASSOC)) {
echo $row['id'] . "\n";
}
?>
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$mdb2->setFetchMode(MDB2_FETCHMODE_ASSOC);
$res =& $mdb2->query('SELECT * FROM users');
while ($row = $res->fetchRow()) {
echo $row['id'] . "\n";
}
?>
行番号による行の取得
PEAR MDB2 のフェッチシステムでは、
fetch 文に対して追加のパラメータを指定することができます。
これにより、結果から行番号を指定して行を取得することができます。
これは、結果セットの一部を表示したり (例えば複数ページにまたがる
HTML のリストなど)、特別な順番で行を取得する場合などに有用です。
<?php
// すでに $res という名前の MDB2_Result オブジェクトが存在するものとします
// 取得を開始する行
$from = 50;
// 1 ページあたりの結果の数
$resPage = 10;
// このページに表示する最後の行
$to = $from + $resPage;
foreach (range($from, $to) as $rowNum) {
if (!($row = $res->fetchRow(MDB2_FETCHMODE_ORDERED, $rowNum))) {
break;
}
echo $row[0] . "\n";
}
?>
結果セット全体の取得
MDB2_Result_Common オブジェクトには、
結果セット全体を読み込むためのメソッド群が用意されています。それが
fetchCol() および
fetchAll() です。
結果セットの開放
結果セットの使用を終えた後にもしスクリプトの処理が続くのなら、
メモリを節約するために結果セットを開放するとよいでしょう。
そのために使用するのが
free() です。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$res =& $mdb2->query('SELECT name, address FROM clients');
while ($row = $res->fetchRow(MDB2_FETCHMODE_ASSOC)) {
echo $row['name'] . ', ' . $row['address'] . "\n";
}
$res->free();
?>
生の結果リソースの取得
あなたが読み込まなければならないデータの形式がまだ MDB2 で実装されていない場合は、
getResource()
メソッドでネイティブな結果セットを取得し、
それに対して PHP の各拡張モジュールの関数を直接コールすることができます
(それによって、当然コードの可搬性は下がります)。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$res =& $mdb2->query('SELECT name, address FROM clients');
$native_result = $res->getResource();
?>
クエリの結果からより詳細な情報を取得する
MDB2 には、クエリの結果セットの情報を取得するための
4 種類の方法があります。
numRows()
は、SELECT クエリの結果の行数を返します。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$res =& $mdb2->query('SELECT * FROM phptest');
if ($mdb2->getOption('result_buffering')) {
echo $res->numRows();
} else {
echo '"result_buffering" が無効になっている場合は、結果セットの行数は取得できません';
}
?>
numCols()
は、SELECT クエリの結果に含まれるカラムの数を返します。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$res =& $mdb2->query('SELECT * FROM phptest');
echo $res->numCols();
?>
rowCount()
は、内部的な行ポインタが、現在何行目を指しているかを返します。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$res =& $mdb2->query('SELECT * FROM phptest');
$res->fetchRow();
// 結果セットに 2 行以上のデータがある場合、これは 2 を返します
echo $res->rowCount();
?>
getColumnNames()
は、連想配列を返します。
結果セットのカラム名が連想配列のキー、
結果セット内でのカラムの位置が連想配列の値となります。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$res =& $mdb2->query('SELECT * FROM phptest');
print_r($res->getColumnNames());
?>
seek()
は、結果セット内の特定の行まで移動します。
既に読み込んだ後の行に戻ることができるのは、'result_buffering'
オプションが有効な場合のみであることに注意しましょう。
それ以外の場合は、先へ進むことしかサポートしていません。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$res =& $mdb2->query('SELECT * FROM phptest');
// 結果セットの 10 番目の行まで移動します
$res->seek(10);
?>
nextResult()
複数のクエリから返された複数の結果セットを順に処理します。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$multi_query = $this->db->setOption('multi_query', true);
// multi_query が有効かどうかを調べます
if (!PEAR::isError($multi_query)) {
$res =& $mdb2->query('SELECT * FROM phptest; SELECT * FROM phptest2;');
$data1 = $res->fetchAll();
// 結果ポインタを、次の結果セットに移動します
$res->nextResult();
$data2 = $res->fetchAll();
} else {
echo 'multi_query オプションがサポートされていません';
}
?>
bindColumn()
は、ユーザ変数への参照を結果セット内の特定のフィールドにバインドします。
つまり、次の行を取得すると、その変数の内容も連動して更新されます。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$name = $address = null;
$res =& $mdb2->query('SELECT id, name, address FROM clients', array('id' => 'integer'));
$res->bindColumn('id', $id);
// query() のコールに含まれていない、カラムの型を指定します
$res->bindColumn('name', $name, 'text');
// 型の指定は、MDB2 においては常に任意です
$res->bindColumn('address', $address);
while ($res->fetchRow()) {
echo "'$name' (ユーザ ID '$id') さんの住所は '$address' です\n";
}
?>
一回のコールによるクエリ実行とデータ取得
すべてのフェッチメソッドには、クエリの実行も同時に行うバージョンのメソッドがあります。それが
queryOne()、
queryRow()、
queryCol() および
queryAll() です。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$data = $mdb2->queryAll('SELECT * FROM phptest');
print_r($data);
?>
プリペアドステートメントを使用したい場合は、
Extended モジュールのメソッド
getOne()、
getRow()、
getCol()、
getAll() および
getAssoc() を使用します。
<?php
// すでに $mdb2 という名前の MDB2 オブジェクトが存在するものとします
$mdb2->loadModule('Extended');
$query = 'SELECT * FROM phptest WHERE id = ?';
$data = $mdb2->extended->getRow($query, null, array(1), array('integer'));
print_r($data);
?>
データ型
MDB2 は、すべてのドライバにまたがる多くのデータ型をサポートしています。
クエリの実行やプリペアの際にこれらを結果セットに設定するには、
setResultTypes() メソッドを使用します。
サポートされるデータ型とその書式についての概要は
こちら を参照ください。
LOB の取得
ラージオブジェクト (BLOB や CLOB) を取得するには、
ストリームを使用します。これは、ファイルを読み込むのと同じような方法です。
<?php
$result =& $mdb2->query('SELECT document, picture FROM files WHERE id = 1', array('clob', 'blob'));
if (PEAR::isError($result) || !$result->valid()) {
// なんてこった
}
$row = $result->fetchRow();
// CLOB を、変数 $clob_value に読み込みます
$clob = $row[0];
if (!PEAR::isError($clob) && is_resource($clob)) {
$clob_value = '';
// ストリームを使用します
while (!feof($clob)) {
$clob_value .= fread($clob, 8192);
}
$mdb2->datatype->destroyLOB($clob);
}
// BLOB を、変数 $blob_value に読み込みます
$blob = $row[1];
if (!PEAR::isError($blob) && is_resource($blob)) {
$blob_value = '';
while (!feof($blob)) {
$blob_value.= fread($blob, 8192);
}
$mdb2->datatype->destroyLOB($blob);
}
// 結果を開放します
$result->free();
?>
エラーチェック
isError()
を使用して、MDB2_Error
オブジェクトが返されていないかどうか調べることを忘れないようにしましょう。