Using Prepared PDO statements - php

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.

Related

Is there a way to use SELECT FOUND_ROWS() in php and mysqli?

I'm trying to implement a pagination system into my website and can't get past this one stubborn error. I'm not exactly sure if you can use FOUND_ROWS() in mysqli as opposed to PDO but that's what I came here for.
I have the latest version of PHP and everything worked up to this point in the pagination.
$stmt = $conn->prepare('SELECT count(*) FROM owned_assets WHERE uid=? AND type=? LIMIT '.$start.', '.$rLim);
$stmt->bind_param('ii', $uid, $assetType);
$stmt->execute();
$total = $conn->query('SELECT FOUND_ROWS() as total')->mysqli_fetch_array()['total'];
What's supposed to happen (so far) is mysql will count the rows found within the matching query and I can work further on from there.
This is my current error:
Fatal error: Uncaught Error: Call to a member function mysqli_fetch_array() on bool
Of course there is but you have to follow the proper routine.
Your current query makes no sense as it counts the number you already know, stored in $rLim (all right not always but that's not the point).
To use FOUND_ROWS() for pagination you must add SQL_CALC_FOUND_ROWS to your query that fetches the data for a single page.
Then you will be able to get the total number of rows without limit by means of running another query with FOUND_ROWS().
That said, using SQL_CALC_FOUND_ROWS is not recommended as it is as slow as fetching all rows without LIMIT. And this is the reason why this function was recently deprecated.
So you have to make two queries, one fetching the actual data with LIMIT clause and one with count(*) and without LIMIT.
You already have the counting query, just fetch that value. No need for another second query FOUND_ROWS().
$stmt = $conn->prepare('SELECT count(*) FROM owned_assets WHERE uid=? AND type=?');
$stmt->bind_param('ii', $uid, $assetType);
$stmt->execute();
$result = $stmt->get_result();
$total = $result->fetch_assoc();
echo $total['count(*)'];
Sidenote: You can use an alias to count(*) AS total in the query, and access the index as $total['total'] in the return value.
You don't need another query to get the total number of rows, as you already have it with COUNT(). You can just bind the result of the first query to the $total with bind_result():
$stmt->bind_result($total);

PHP PDO How does rowCount() get it's results?

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.

How to combine two PDO statements in one MySQL query?

From what I know now about PDO statements and my own experiences on localhost and Google - there are some difficulties with using multiple PDO statements in one query. For instance this situation:
$stmt = $db_people->prepare("SELECT * FROM people WHERE online=1");
$stmt->execute();
$results_people = $stmt->fetch(PDO::FETCH_ASSOC);
On this query I can do simple PDO statement like fetch (in example). But when I want to use PDO statement like this:
$rows = $stmt->rowCount();
It is not possible and the statement will not return the right number of rows. When I do it in the other way around and filling one of the column name - rowCount works correctly like this:
$stmt = $db_people->prepare("SELECT name FROM people WHERE online=1");
$stmt->execute();
$rows = $stmt->rowCount();
And adding fetch after that like this:
$results_people = $stmt->fetch(PDO::FETCH_ASSOC);
Will not work corectly in this example. My question is - How to combine two different PDO statements in one single query? Thank you.
The answer probably depends on which operations you're trying to combine. For instance, if you're trying to combine PDOStatement::rowCount() with a SELECT SQL operation, then it's probably worthwhile to take notice of the warnings in the PDOStatement::rowCount() description which says that rowCount() is not 100% reliable for SELECT statements in all databases.
If the problem you're trying to solve is specifically limited to counting the result rows of a SELECT, then another approach would be to use PDOStatement::fetchAll() and count the rows in the returned array.

Get Number of Rows from a Select Statement Efficiently

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.

Get Number of Rows from a Select statement

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.

Categories