When using PHP's PDO (PHP Data Objects) for database development, PDOStatement::rowCount() is often used to obtain the number of rows affected by the query, especially after executing UPDATE , DELETE and other statements. However, in some scenarios, its return results can feel "misleading" or even buggy.
This article will dig deeper into why rowCount() is sometimes not as we expected, revealing the reasons behind it, and giving the correct way to deal with it.
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password');
$stmt = $pdo->prepare("DELETE FROM users WHERE id = :id");
$stmt->execute([':id' => 123]);
echo $stmt->rowCount(); // Output the number of deleted lines
In this code, we deleted a record and hope to know through rowCount() that several records are affected. This usually works fine for DELETE and UPDATE statements. However, once SELECT statements or some special situations are involved, the problem arises.
Although rowCount() is supported for SELECT queries by some databases such as PostgreSQL, calling rowCount() after SELECT in MySQL will usually return 0 . The reason is that PDO uses MYSQL_ATTR_USE_BUFFERED_QUERY by default in MySQL. The rows are extracted delayedly, and rowCount cannot accurately know the number of rows.
$stmt = $pdo->query("SELECT * FROM users");
echo $stmt->rowCount(); // exist MySQL Possible output 0
Even if the statement is executed legally, as long as there is no actual change in the database, rowCount() returns 0. For example:
$stmt = $pdo->prepare("UPDATE users SET name = :name WHERE id = :id");
$stmt->execute([':name' => 'Alice', ':id' => 123]);
echo $stmt->rowCount(); // if name Already Alice,Then return 0
This is not an error, but a feature of SQL: without actual changes, it does not count as "influence" the line.
Different database driver implementations support rowCount() inconsistently. For example:
MySQL: SELECT does not return the correct value, UPDATE/DELETE supports it.
PostgreSQL: Most statements support it.
SQLite: Most statements support it.
Oracle: The behavior is more complicated and you need to be used with caution.
$stmt = $pdo->query("SELECT * FROM users WHERE status = 'active'");
$rows = $stmt->fetchAll();
echo count($rows);
Or use traversal:
$count = 0;
foreach ($stmt as $row) {
$count++;
}
echo $count;
$stmt = $pdo->prepare("UPDATE users SET name = :name WHERE id = :id AND name != :name");
$stmt->execute([':name' => 'Alice', ':id' => 123]);
echo $stmt->rowCount(); // Only when name Return to actual change 1
In many cases, especially in queries or batch operations, it is better to let SQL return the number of rows affected directly:
$stmt = $pdo->query("SELECT COUNT(*) FROM users WHERE status = 'active'");
$count = $stmt->fetchColumn();
echo $count;
Never assume that all drivers behave consistently. You can use the following methods to detect or set compatibility when initializing PDO:
$pdo = new PDO('mysql:host=localhost;dbname=testdb', 'user', 'password', [
PDO::MYSQL_ATTR_USE_BUFFERED_QUERY => true
]);
Although PDOStatement::rowCount() is a commonly used interface, it does not always act as you wish in different databases and different SQL types. As a developer, understanding its scope and limitations is the key to avoiding pitfalls.
The safest strategy is:
Avoid relying on rowCount() in SELECT queries;
For operations such as UPDATE/DELETE , it is understood that "affecting rows" is not "finding rows";
For precise control or cross-database compatibility, consider using SQL-level counting logic.