Introduction - Results

Introduction - Results -- Obtaining data from query results

Description

Fetching Individual Rows From Query Results

The MDB2_Result_Common object provides two methods for fetching data from rows of a result set: fetchOne(), fetchRow(), fetchCol() and fetchAll().

fetchRow() and fetchOne() read an entire row or a single column respectively. The result pointer gets moved to the next row each time these methods are called. NULL is returned when the end of the result set is reached.

fetchRow() reads an entire row as an array and fetchOne() reads an single column into a scalar. The result pointer gets moved to the next row each time these methods are called. NULL is returned when the end of the result set is reached.

MDB2_Error is returned if an error is encountered.

Formats of Fetched Rows

The data from the row of a query result can be placed into one of three constructs: an ordered array (with column numbers as keys), an associative array (with column names as keys) or an object (with column names as properties).

MDB2_FETCHMODE_ORDERED (default)
Array
(
    [0] => 28
    [1] => hi
)

MDB2_FETCHMODE_ASSOC
Array
(
    [a] => 28
    [b] => hi
)

MDB2_FETCHMODE_OBJECT
stdClass Object
(
    [a] => 28
    [b] => hi
)

NOTE: When a query contains the same column name more than once (such as when joining tables which have duplicate column names) and the fetch mode is MDB2_FETCHMODE_ASSOC or MDB2_FETCHMODE_OBJECT, the data from the last column with a given name will be the one returned. There are two immediate options to work around this issue:

Use aliases in your query, for example People.Name AS PersonName
Change the fetch mode to MDB2_FETCHMODE_ORDERED

TIP: If you are running into this issue, it likely indicates poor planning of the database schema. Either data is needlessly being duplicated or the same names are being used for different kinds of data.

How to Set Formats

You can set the fetch mode each time you call a fetch method and/or you can set the default fetch mode for the whole MDB2 instance by using the setFetchMode() method.

Fetch Rows by Number

The PEAR MDB2 fetch system also supports an extra parameter to the fetch statement. So you can fetch rows from a result by number. This is especially helpful if you only want to show sets of an entire result (for example in building paginated HTML lists), fetch rows in an special order, etc.

Getting Entire Result Sets

The MDB2_Result_Common object provides several methods to read entire results sets: fetchCol() and fetchAll().

Freeing Result Sets

Once you finish using a result set, if your script continues for a while, it's a good idea to save memory by freeing the result set via Use free().

Getting the native result resource

If whatever data you need to read from a result set is not yet implemented in MDB2 you can get the native result resource using the getResource() method and then call the underlying PHP extension directly (though this would of course require that it is not upto you to make this sufficiently portable).

Getting More Information From Query Results

With MDB2 there are four ways to retrieve useful information about the query result sets themselves:

Example 33-7. numRows() tells how many rows are in a SELECT query result

<?php
// Once you have a valid MDB2 object named $mdb2...
$res =& $mdb2->query('SELECT * FROM phptest');
if ($mdb2->getOption('result_buffering')) {
    echo $res->numRows();
} else {
    echo 'cannot get number of rows in the result set when "result_buffering" is disabled';
}
?>

Example 33-8. numCols() tells how many columns are in a SELECT query result

<?php
// Once you have a valid MDB2 object named $mdb2...
$res =& $mdb2->query('SELECT * FROM phptest');
echo $res->numCols();
?>

Example 33-9. rowCount() tells which row number the internal result row pointer currently points to

<?php
// Once you have a valid MDB2 object named $mdb2...
$res =& $mdb2->query('SELECT * FROM phptest');
$res->fetchRow();
// returns 2 if the result set contains at least 2 rows
echo $res->rowCount();

?>

Example 33-10. getColumnNames() returns an associative array with the names of the column of the result set as keys and the position inside the result set as the values

<?php
// Once you have a valid MDB2 object named $mdb2...
$res =& $mdb2->query('SELECT * FROM phptest');
print_r($res->getColumnNames());

?>

Example 33-11. seek() allows to seek to a specific row inside a result set. Note that seeking to previously read rows is only possible if the 'result_buffering' option is left enabled, otherwise only forward seeking is supported.

<?php
// Once you have a valid MDB2 object named $mdb2...
$res =& $mdb2->query('SELECT * FROM phptest');
// Seek to the 10th row in the result set
$res->seek(10));

?>

Example 33-12. nextResult() allows iterate over multiple results returned by a multi query.

<?php
// Once you have a valid MDB2 object named $mdb2...
$multi_query = $this->db->setOption('multi_query', true);
// check if multi_query can be enabled
if (!PEAR::isError($multi_query)) {
    $res =& $mdb2->query('SELECT * FROM phptest; SELECT * FROM phptest2;');
    $data1 = $res->fetchAll();
    // move result pointer to the next result
    $res->nextResult();
    $data2 = $res->fetchAll();
} else {
    echo 'multi_query option is not supported';
}

?>

Example 33-13. bindColumn() allows to bind a reference to a user variable to a specific field inside the result set. This means that when fetching the next row, this variable is automatically updated.

<?php
// Once you have a valid MDB2 object named $mdb2...
$name = $address = null;
$res =& $mdb2->query('SELECT id, name, address FROM clients', array('id' => 'integer'));
$res->bindColumn('id', $name);
// provide a type for the column not included in the query() call
$res->bindColumn('id', $name, 'text');
// but specifying a type is as always optional in MDB2
$res->bindColumn('address', $address);
while ($res->fetchRow()) {
    echo "The address of '$name' (user id '$id') is '$address'\n";
}
?>

Querying and fetching in one call

All of the fetch methods are also available in a variant that executes a query directly: queryOne(), queryRow(), queryCol() and queryAll().

Users that prefer to use prepared statements can make use of the following methods from the Extended module: getOne(), getRow(), getCol(), getAll() and getAssoc().

Data types

MDB2 supports a number of data types across all drivers. These can be set for result sets at query or prepare time or using the setResultTypes() method. You can find an overview of the supported data types and their format here.

Checking for Errors

Don't forget to use isError() to check if your actions return a MDB2_Error object.