結果

結果 – クエリ結果からのデータの取得

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($querynull, array(1), array('integer'));
print_r($data);

?>

データ型

MDB2 は、すべてのドライバにまたがる多くのデータ型をサポートしています。 クエリの実行やプリペアの際にこれらを結果セットに設定するには、 setResultTypes() メソッドを使用します。 サポートされるデータ型とその書式についての概要は こちら を参照ください。

LOB の取得

ラージオブジェクト (BLOB や CLOB) を取得するには、 ストリームを使用します。これは、ファイルを読み込むのと同じような方法です。

ストリームを使用した LOB の取得

<?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($clob8192);
    }
    
$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($blob8192);
    }
    
$mdb2->datatype->destroyLOB($blob);
}

// 結果を開放します
$result->free();
?>

エラーチェック

isError() を使用して、MDB2_Error オブジェクトが返されていないかどうか調べることを忘れないようにしましょう。

データ型の処理の概要 (Previous) プリペアドステートメント (Next)
Last updated: Fri, 28 Nov 2014 — Download Documentation
Do you think that something on this page is wrong? Please file a bug report or add a note.
View this page in:

User Notes:

Note by: mckenna
Insert/Update Clob/Blob Fields.

The documentation is not very clear about it, and it took me some time to figure it out with oracle. Maybe it will help others too.

To insert/update a lob field it seems that you have to use prepare and execute. First you have to prepare your query and use as type clob or blob for the field. With the statement call execute and you have two ways to use it.

1. as the value pass a handle to the data that you want to insert/update. MDB2 will read the hole data and save it.
2. as the value pass the complete file path with file:// at the beginning. MDB2 will pass the filename automatically and the db api will read the content.

If you use the second method don't forget to set the option lob_allow_url_include to 1 or true. Otherwise you may find the filename in your db instead.

$mdb2->setOption('lob_allow_url_include', 1);
$sql = "insert into myfiles (name, content) values (:name, :content)";
$types = array('text', 'blob');
$stmt = $mdb2->prepare($sql, $types, MDB2_PREPARE_MANIP);

$data = array('my_uploaded_file.txt', 'file:///tmp/upload/yxc');
$result = $stmt->execute($data);

With oracle it is best to use named binding with the same name of the lob column. Index binding may result in an inconsistent types lob and number error. MDB2 will only use the right part of the file name after file://.