Does PHP's PDO run a silent select count(*) statement for it's rowCount() when used after a select statement, or does it get it's result using some other approach?
$query = $conn->prepare('select name, alias from accounts where status = 0');
$query->execute();
$queryCount = $query->rowCount();
$profiles = $query->fetchAll(PDO::FETCH_ASSOC);
if($queryCount > 0) {
print_r($profiles);
} else {
echo 'No records found';
}
In the above code, everything runs fine, and I'm able to get the correct number of rows as the result. But is there a count statement running in there? How does PHP do this?
That depends on the PDO database driver really. Despite what the manual says, it usually works for MySQL connections. With recent versions of mysqlnd anyway. Older versions and the old libmysqlclient interface can be initialized with PDO::MYSQL_ATTR_FOUND_ROWS to also return row counts for SELECT statements.
There's no automatic SELECT COUNT() requery when you ask for ->rowCount(). The driver receives and keeps a uint64_t row_count; internally. Server responses pretty much always include a result row count for prepared statements.
For ->fetchAll and iterations, the PDO mysqlnd driver even just manually set->row_count++ calculates it.
Have a look at https://github.com/php/php-src/blob/master/ext/mysqlnd/mysqlnd_result.c for what's actually happening.
The older mysql driver calls mysql_num_rows.c which only returns the correct result count after all rows have been fetched.
From here:
Example #2 Counting rows returned by a SELECT statement
For most databases, PDOStatement::rowCount() does not return the
number of rows affected by a SELECT statement.
Means: you may not rely on what you have currently implemented!
No. From the docs:
For most databases, PDOStatement::rowCount() does not return the number of rows affected by a SELECT statement. Instead, use PDO::query() to issue a SELECT COUNT(*) statement with the same predicates as your intended SELECT statement, then use PDOStatement::fetchColumn() to retrieve the number of rows that will be returned. Your application can then perform the correct action.
In the deprecated PHP function mysql_num_rows(), the MySQL function mysql_num_rows() was used. I suppose PDO does the same.
More information can be found here.
NB: this means that your current code may work in some cases, but you can't rely on it. Use a COUNT(*) query instead.
From PHP's docs:
PDOStatement::rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.
Related
I'm running queries using the PDO prepared statement, MySQL db. When I run a query, I haven't found a way to know the number of affected rows if any, I've tried rowCount() but still to no avail.
$stmt1 = $db->prepare("SELECT * FROM publications WHERE pub_journal = '$j' AND pub_issue = 'CURRENT'");
$stmt1->execute();
How can I find the number of affected rows?
rowCount should work if your database is MySQL. The fact that it hasn't worked for you indicates that your query may be failing, or that it does not return the number of rows you expect it to.
The PDO documentation suggests the following approach to find the number of rows:
For most databases, PDOStatement::rowCount() does not return the number of rows affected by a SELECT statement. Instead, use PDO::query() to issue a SELECT COUNT(*) statement with the same predicates as your intended SELECT statement, then use PDOStatement::fetchColumn() to retrieve the number of rows that will be returned.
This should work with a prepared statement as well as with PDO::query().
You can modify your original SQL to be used as a template, so that it can take either COUNT(*) or * (or even better, a list of the specific columns you need).
$sql = "SELECT %s FROM publications WHERE pub_journal = ? AND pub_issue = 'CURRENT'";
Notice the ? in the SQL. This is a placeholder to which the $j variable will be bound when the statement is executed with execute([$j]);. When you concatenate your variables into the SQL string (like ...WHERE pub_journal = '$j'...) you really aren't getting much of the benefit of prepared statements.
With this, you can prepare and execute your count query:
$count_stmt = $db->prepare(sprintf($sql, 'COUNT(*)'));
$count_stmt->execute([$j]);
Then get the count with:
$count = $count_stmt->fetchColumn();
After you do whatever you need to do with the count, you can execute the actual SELECT query by specifying which columns you want rather than COUNT(*).
$select_stmt = $db->prepare(sprintf($sql, '*'));
$select_stmt->execute([$j]);
rowcount() should only be used for DELETE, INSERT, or UPDATE statements, though it may work for SELECTs in some cases. What you can do is this, though:
$res = $stmt->fetchAll();
$count = count($res);
And $count will hold the number of rows.
The PHP docs for mysqli_num_rows says
Returns the number of rows in the result set.
The PHP docs for mysqli_affected_rows says
Returns the number of rows affected by the last INSERT, UPDATE, REPLACE or DELETE query.
_num_rows is called on a result, and _affected_rows is called on a connection. Since I think they do the same thing(correct this assumption if I'm wrong), I'm wondering whether one works better than the other, and which situations would call for which function.
Aren't number of rows affected and number of rows in the result set synonymous?
num_rows tells you how many rows there are in the result set you just selected with a SELECT query. affected_rows tells you how many rows where affected by an INSERT, UPDATE, REPLACE or DELETE query. The difference is obvious:
$resultSet = mysqli_query($c, 'SELECT ...');
echo mysqli_num_rows($resultSet);
SELECT result set goes into num_rows.
mysqli_query($c, 'UPDATE ...');
echo mysqli_affected_rows($c);
No result set, no num_rows.
mysql_affect_rows counts on how many rows your UPDATE/INSERT query was used
and mysql_num_rows counts how many rows your SELECT statement found
I'd like to add, in recent versions of mysql this may have changed.
I was recently looking for the difference and found that while yes mysqli_num_rows counts how many rows your SELECT statement found.
mysqli_affected_rows will count how many rows your UPDATE/INSERT/DELETE/REPLACE and SELECT statement 'affected'.
Unless you are trying to compare between the number of rows returned in a SELECT statement vs. the number of rows affected in an UPDATE/INSERT/DELETE/REPLACE than there is no huge concern over which you need to be using. If you want to be semantically correct than use the appropriate one for the corresponding statement.
https://dev.mysql.com/doc/refman/8.0/en/mysql-affected-rows.html
For SELECT statements, mysql_affected_rows()
works like mysql_num_rows()
Until recently I've been using mysql_real_escape_string() to fix most of my variables before making SQL queries to my database. A friend said that I should be using PDO's prepared statements instead, so after reading a bit about them I'm now switching over to them.
I've only encountered one problem so far in switching over, and that's counting the rows to returned by a SELECT statement. On occasion in my code, I'd run an SQL query and then count the number of rows returned from the SELECT statement. Depending on whether a result set returned, I would take different actions. Sometimes I do need to use the result set from it. MySQL let me go straight to mysql_fetch_assoc() after mysql_num_rows() with no problem. However, PDO doesn't seem to have anything like mysql_num_rows().
I've been reading some responses on SO that gave me a solution, to either use COUNT() in the SQL statement or to use the PHP function count() on the result set. COUNT() would work fine in the SQL statement if I didn't need the result set in some places, however, several people have mentioned that using count() on the result set is fairly inefficient.
So my question is, how should I be doing this if I need to count the number of rows selected (if any), then run a script with the result set? Is using count() on the result set the only way in this case, or is there a more efficient way to do things?
Below is a short example of something similar to my previous SQL code:
$query=mysql_query('SELECT ID FROM Table WHERE Name='Paul' LIMIT 1);
if(mysql_num_rows($query)>0)
{
print_r(mysql_fetch_assoc($query));
}
else
{
//Other code.
}
Thanks.
EDIT
I do know that you use fetchAll() on the statement before counting the result set (which gives me what I need), but I'm just trying to figure out the most efficient way to do things.
$stmt->rowCount();
http://php.net/manual/en/pdostatement.rowcount.php
the rows must be fetched(buffered into memory, or iterated) for it to work. It's not uncommon for your pdo driver to be configured to do this automatically.
You will have to use Count(). You can run two queries like
SELECT COUNT(ID) FROM Table WHERE Name='Paul'
one you have get the count, then run the query with select clause
SELECT ID FROM Table WHERE Name='Paul' LIMIT 1
Count() function is not inefficient at all if you are using it like COUNT(ID), because most probably id is primary key and have an index. MYSQL wont even have to access the table.
I have this:
$dbh = new PDO("odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq=$mdbFilename", $username, $password);
$sql = "SELECT * FROM this_table";
$stmt = $dbh->query($sql);
//num of rows?
How do I get the number of rows returned from that SELECT statement?
Thanks all
SELECT count(*) FROM this_table is an option...
Regarding rowCount:
PDOStatement::rowCount() returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.
If the last SQL statement executed by the associated PDOStatement was a SELECT statement, some databases may return the number of rows returned by that statement. **
However, this behaviour is not guaranteed for all databases and should not be relied on for portable applications.
I have found a solution, using fetchAll and then using count on this array - which is what MySQL does anyway internally, a bit inefficient but it works for me.
$q = $db->query("SELECT ...");
$rows = $q->fetchAll();
$rowCount = count($rows);
From another question Chad provided this insight:
It seems as though the only reason
this was possible with MySQL is
because it internally fetched all the
result rows and buffered them, to be
able to give you this information. See
mysql_unbuffered_query(). If you use
that function instead of
mysql_query(), the mysql_num_rows()
function will not work. If you really
need to know the number of rows while
using PDO, you can fetch all of the
rows from PDO into an array and then
use count().
Hope this is useful to someone.
I've recently started work on a new project using PHP5 and want to use their PDO classes for it. The problem is that the MySQL PDO Driver doesn't support rowCount() so there's no way to run a query and then get the number of affected rows, or rows returned, which is a pretty big issue as far as I'm concerned. I was wondering if anyone else has dealt with this before and what you've done to work around it. Having to do a fetch() or fetchAll() to check if any rows were affected or returned seems like a hack to me, I'd rather just do $stmt->numRows() or something similar.
You can issue a SELECT FOUND_ROWS() query right after the original SELECT query to get row count.
$pdo->query("SELECT * FROM users");
$foundRows = $pdo->query("SELECT FOUND_ROWS()")->fetchColumn();
See also: MySQL Docs on FOUND_ROWS()
For those of you who are using MySQL stored procedures, this solution isn't really feasible. What I would suggest that you do is have your stored procedure create two rowsets. The first one will contain one row and one column, containing the number of records. The second will be the recordset you will use for fetching that number of rows.
The number of unlimited rows can be a SELECT COUNT(*) with the exact same WHERE clause as the second rowset without the LIMIT/OFFSET clauses.
Another idea could be to create a temporary table. Use your SELECT statement to populate the temporary table. Then you can use SELECT COUNT(*) FROM tmpTable for your first rowset and SELECT * FROM tmpTable for your second.
This question is based on several false assumptions and one outdated statement.
First of all, do not confuse number of affected and selected rows. PDO supported the former even back in '09.
Speaking of number of rows returned by SELECT statement - you just don't need that number. The data you have is enough.
And yeah, nowadays rowCount() supports number of rows selected from mysql as well. But again - you don't need that number in an average web-application anyway.