There are many conflicting statements around. What is the best way to get the row count using PDO in PHP? Before using PDO, I just simply used mysql_num_rows
.
A quick one liner to get the first entry returned. This is nice for very basic queries.
<?php
$count = current($db->query("select count(*) from table")->fetch());
?>
Reference
As it often happens, this question is confusing as hell. People are coming here having two different tasks in mind:
That's two absolutely different tasks that have nothing in common and cannot be solved by the same function. Ironically, for neither of them the actual PDOStatement::rowCount()
function has to be used.
Let's see why
Before using PDO I just simply used
mysql_num_rows()
.
Means you already did it wrong. Using mysql_num_rows()
or rowCount()
to count the number of rows in the table is a real disaster in terms of consuming the server resources. A database has to read all the rows from the disk, consume the memory on the database server, then send all this heap of data to PHP, consuming PHP process' memory as well, burdening your server with absolute no reason.
Besides, selecting rows only to count them simply makes no sense. A count(*)
query has to be run instead. The database will count the records out of the index, without reading the actual rows and then only one row returned.
For this purpose the code suggested in the accepted answer is fair, save for the fact it won't be an "extra" query but the only query to run.
The second use case is not as disastrous as rather pointless: in case you need to know whether your query returned any data, you always have the data itself!
Say, if you are selecting only one row. All right, you can use the fetched row as a flag:
$stmt->execute();
$row = $stmt->fetch();
if (!$row) { // here! as simple as that
echo 'No data found';
}
In case you need to get many rows, then you can use fetchAll()
.
fetchAll()
is something I won't want as I may sometimes be dealing with large datasets
Yes of course, for the first use case it would be twice as bad. But as we learned already, just don't select the rows only to count them, neither with rowCount()
nor fetchAll()
.
But in case you are going to actually use the rows selected, there is nothing wrong in using fetchAll()
. Remember that in a web application you should never select a huge amount of rows. Only rows that will be actually used on a web page should be selected, hence you've got to use LIMIT
, WHERE
or a similar clause in your SQL. And for such a moderate amount of data it's all right to use fetchAll()
. And again, just use this function's result in the condition:
$stmt->execute();
$data = $stmt->fetchAll();
if (!$data) { // again, no rowCount() is needed!
echo 'No data found';
}
And of course it will be absolute madness to run an extra query only to tell whether your other query returned any rows, as it suggested in the two top answers.
In such a rare case when you need to select a real huge amount of rows (in a console application for example), you have to use an unbuffered query, in order to reduce the amount of memory used. But this is the actual case when rowCount()
won't be available, thus there is no use for this function as well.
Hence, that's the only use case when you may possibly need to run an extra query, in case you'd need to know a close estimate for the number of rows selected.
There is a simple solution. If you use PDO connect to your DB like this:
try {
$handler = new PDO('mysql:host=localhost;dbname=name_of_your_db', 'your_login', 'your_password');
$handler -> setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch (PDOException $e) {
echo $e->getMessage();
}
Then, the query to DB will be:
$query = $handler->query("SELECT id FROM your_table WHERE ...");
And finally, to count the rows matching your query write like this
$amountOfRows = $query->rowcount();
Here's a custom-made extension of the PDO class, with a helper function to retrieve the number of rows included by the last query's "WHERE" criteria.
You may need to add more 'handlers', though, depending on what commands you use. Right now it only works for queries that use "FROM " or "UPDATE ".
class PDO_V extends PDO
{
private $lastQuery = null;
public function query($query)
{
$this->lastQuery = $query;
return parent::query($query);
}
public function getLastQueryRowCount()
{
$lastQuery = $this->lastQuery;
$commandBeforeTableName = null;
if (strpos($lastQuery, 'FROM') !== false)
$commandBeforeTableName = 'FROM';
if (strpos($lastQuery, 'UPDATE') !== false)
$commandBeforeTableName = 'UPDATE';
$after = substr($lastQuery, strpos($lastQuery, $commandBeforeTableName) + (strlen($commandBeforeTableName) + 1));
$table = substr($after, 0, strpos($after, ' '));
$wherePart = substr($lastQuery, strpos($lastQuery, 'WHERE'));
$result = parent::query("SELECT COUNT(*) FROM $table " . $wherePart);
if ($result == null)
return 0;
return $result->fetchColumn();
}
}
This is an old post, but getting frustrated looking for alternatives. It is super unfortunate that PDO lacks this feature, especially as PHP and MySQL tend to go hand in hand.
There is an unfortunate flaw in using fetchColumn() as you can no longer use that result set (effectively) as the fetchColumn() moves the needle to the next row. So for example, if you have a result similar to
If you use fetchColumn() you can find out that there are 3 fruits returned, but if you now loop through the result, you only have two columns, The price of fetchColumn() is the loss of the first column of results just to find out how many rows were returned. That leads to sloppy coding, and totally error ridden results if implemented.
So now, using fetchColumn() you have to implement and entirely new call and MySQL query just to get a fresh working result set. (which hopefully hasn't changed since your last query), I know, unlikely, but it can happen. Also, the overhead of dual queries on all row count validation. Which for this example is small, but parsing 2 million rows on a joined query, not a pleasant price to pay.
I love PHP and support everyone involved in its development as well as the community at large using PHP on a daily basis, but really hope this is addressed in future releases. This is 'really' my only complaint with PHP PDO, which otherwise is a great class.