Simplest method to retrieve single (and only) row in SQLite using PDO - php

I have this PDO
$stmt = $db->prepare('SELECT * FROM channels WHERE id=:id');
$stmt->bindValue(':id', $id, SQLITE3_INTEGER);
$result = $stmt->execute();
What now is the simplest method to access the row returned using $row['column_name']?
I know that for sure the query will only ever return a single row as it's impossible to have more than 1 row with the same id so I am looking to keep the code as simple as possible to access that row.
Examples I've seen online are quite long and complex, using while loops to loop through rows etc. that I don't need.

It should be as simple as
$row = $stmt->fetch(PDO::FETCH_ASSOC);
The examples you've seen probably have something more like
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) { ...
because they're designed to process a query result with multiple rows. But if you know you'll only ever have one row, you can just forgo the loop. Of course, this is assuming your query actually executed successfully and returned a result. It would be a good idea to at least check
if ($row) { ...
before you try to use it in your subsequent code.

Related

How to get row count & loop through the result set

I've recently gotten over my bad habit of using the deprecated mysql functions in favor of mysqli, and I'm having some issues.
Right now, I'm using something similar to the following:
$query = $conn->prepare("SELECT * FROM table WHERE cid = ?");
$query->bind_param('i', $id);
$query->execute();
And this is where I get stuck. In order to loop through the result, I use:
while ($row = $query->get_result()->fetch_assoc()) {
//My code here
}
However, I need to determine the number of rows returned from the query before going through the results. To do this, I need to do the following:
$query->store_result();
$rows = $query->num_rows;
But I get errors when calling both get_result and store_result on the same query.. is there an easier way to do this? Am I overthinking things? I basically just want to determine if the result set has greater than x # of rows, and if so, loop through the results.
Thanks for any help.

Multiple Nested query issue, possible to do it in sql?

I asked a question earlier on today regards to Running multiple queries in loop, and building multidimensional array This code that I wrote works, but it just doesn't feel right.
The main issue I was noticing is that to do what I needed to do involved nesting queries inside the loop over of the results of a previous query. This seemed to kick up a stink of errors once I did this more than once, and after a little google time it seems that this just isn't possible to do. So I broke the queries apart and used a for loop for the second query. But this just feels messy, I'm now running two loops and I'm sure there must be a better way of doing this. Some code:
// get all to be done by each user
$stmt = $conn->prepare("SELECT activityId FROM done WHERE userId=? ORDER BY number DESC");
$stmt->bind_param("s", $idq);
$stmt->execute();
$stmt->bind_result($aiddo);
$stmt->store_result();
$num_do = $stmt->num_rows;
while($stmt->fetch()) {
$activityId_do[] = $aiddo;
}
// get location information
for($i=0; $i<=$num_do; $i++) {
$act_done = $conn->prepare("SELECT fullAddress FROM `activity` WHERE (id=?)");
$act_done->bind_param("s",$activityId_do[$i]);
$act_done->execute();
$act_done->bind_result($fullAddress);
while($act_done->fetch()) {
$do_array[] = array(
"fullAddress"=>$fullAddress,
"type"=>"do"
);
}
}
So this code above is inside a while loop over the results on a query that gets all the users a user is following.
I was wondering if there is a better way of doing this, is it possible to use some kind of sql magic on it and do it all in the query?

Using PDO, do I really need to run two separate prepared statements to get the number of rows returned?

What is the preferred method for getting the number of rows that are returned for a SELECT state when using PDO with prepared statements?
I am currently using rowCount() but the docs say I shouldn't be using that since "most databases" don't support it (It is actually working just fine for me, so I'm tempted to keep using it. I can't find any sources that list exactly which databases do not support it, but apparently mine is fine).
Instead they recommend I use fetchColumn() but that requires writing a completely separate SQL statement that includes the COUNT(*) in my sql statement.
This is what they propose (http://php.net/manual/en/pdostatement.rowcount.php#example-1038):
//SQL TO GET ROWS TO OUTPUT
$sql = 'SELECT *
FROM properties
WHERE lister_id = :lister_id
AND lister_type = "landlord"';
$result = $dbh->prepare($sql);
$result->bindParam(':lister_id', $_SESSION['loggedin_lister_id'], PDO::PARAM_INT);
$result->execute();
//SQL TO GET NUMBER OF RETURNED ROWS
$row_num_sql = 'SELECT COUNT(*)
FROM properties
WHERE lister_id = :lister_id
AND lister_type = "landlord"';
$row_num_result = $dbh->prepare($row_num_sql);
$row_num_result->bindParam(':lister_id', $_SESSION['loggedin_lister_id'], PDO::PARAM_INT);
$row_num_result->execute();
$num_rows = $row_num_result->fetchColumn();
if($num_rows > 0) {
while($row = $result->fetch(PDO::FETCH_ASSOC)) {
echo $row['name'];
}
}
I find this method that requires me to write a separate and nearly identical sql statement to be redundant and a serious pain when using prepared statements. I can understand how this approach might be acceptable when using a short SQL statement with a basic query, but not in the case of a prepared statement.
1. Is there any other way I can use the fetchColumn() approach
without having to rewrite what is almost exactly the same code?
2. Where can I find an official list of which databases
rowCount() supports when using a SELECT statement? And since it is
working on the database I am currently using, can I assume it is safe
to use(assuming I am not updating my database anytime soon)?
If you don't want to use rowCount I'm think you should two query, or you can use fetchAll and count(fetchAll) for rowCount
the second way, Use SELECT *,COUNT(*) ...

PDO “Uncaught exception 'PDOException' .. Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll().”

I know this question has been asked many times, but I've read the answers to many of the questions and still cannot understand why I am receiving this error:
Fatal error: Uncaught exception 'PDOException' with message
'SQLSTATE[HY000]: General error: 2014 Cannot execute queries while
other unbuffered queries are active. Consider using
PDOStatement::fetchAll(). Alternatively, if your code is only ever
going to run against mysql, you may enable query buffering by setting
the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.'
The first thing that is odd, is that I do not get an error on my localhost (wampserver), but I do get it on my web server. The php version on my localhost is 5.3.10, and on my web server it is 5.3.13.
I have read that the source of this error is making a query when data left in the buffer from a previous query. This is not the case for me -- I have echo'd out all of the data and I know for a fact that every row returned in a query is being fetched.
With that said, I have found that changing one of my queries to fetchAll instead of fetch fixes the problem, but it simply makes no since because I know that all of the rows returned are being read. When I used fetchAll for the query (it is being made in a loop), I printed out the array each loop, and only one item was in the array for each query in the loop.
One more piece of information. It's not the query that I changed to fetchAll (which makes the error go away) that throws the PDO error, there is another query later in my php file that throws the error. My file is basically like this:
... code ...
query 1
... code ...
loop
query 2
end loop
... code ...
query 3
If I comment out query 3, there is no error. If I comment out, or change to fetchAll, query 2, there is no error. query 1 has no affect whatsoever.
I would also like to add that I have tried adding LIMIT 1 to all of the queries on the page (at the same time), and the error is still there. I think this proves there is not unread data in the buffer, right?
I'm really confused, so I would appreciate your advice. Before someone asks, I can't post the full code for this, but here is a simplified version of my code:
$stmt = $this->db->prepare('SELECT ... :par LIMIT 1');
makeQuery($stmt, array(':par' => $var));
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt = $this->db->prepare('SELECT ... :par LIMIT 1');
for loop
makeQuery($stmt, array(':par' => $var));
$row2 = $stmt->fetch(PDO::FETCH_ASSOC);
... [use row2] ...
end for loop
$stmt = $this->db->prepare('SELECT ... :par LIMIT 1');
makeQuery($stmt, array(':par' => $var));
$row3 = $stmt->fetch(PDO::FETCH_ASSOC);
Here is makeQuery().
/**************************************************************************************************************
* Function: makeQuery *
* Desc: Makes a PDO query. *
* Pre conditions: The statement/query and an array of named parameters (may be empty) must be passed. *
* Post conditions: The PDO query is executed. Exceptions are caught, displayed, and page execution stopped. *
**************************************************************************************************************/
function makeQuery($stmt, $array, $errMsg = '')
{
try
{
$stmt->execute($array);
}
catch (PDOException $e)
{
print $errMsg != ''?$errMsg:"Error!: " . $e->getMessage() . "<br/>";
die();
}
}
Thanks for your help!
EDIT: I also tried doing the following after query 2 (since that seems to be the source of the problem:
$row2 = $stmt->fetch(PDO::FETCH_ASSOC); var_dump($row2);
The output was:
bool(false)
Have I stumbled across a PDO bug?
You need to fetch until a row fetch attempt fails. I know you may only have one row in the result set and think one fetch is enough, but its not (when you're using unbuffered queries). PDO doesn't know how many rows there are until it reaches the end, where it tries to fetch the next row, but it fails.
You probably have other statements where you didn't fully "fetch until a fetch failed". Yes, I see that you fetch until the fetch failed for one of the statements, but that doesn't mean you did it for all of them.
To clarify -
When you execute a query via execute(), you create a result set that must be fetched from the db into php. PDO can only handle 1 of these "result set in progress of being fetched" at a time (per connection). You need to completely fetch the result set, all the way to the end of it, before you can start fetching a different result set from a different call to execute().
When you "call fetch() until a fetch() fails", the fact that you reached the end of the results is internally noted by PDO when that final call to fetch() fails due to there being no more results. PDO is then satisfied that the results are fully fetched, and it can clean up whatever internal resources between php and the db that were established for that result set, allowing you to make/fetch other queries.
There's other ways to make PDO "call fetch() until a fetch() fails".
Just use fetchAll(), which simply fetches all rows, and so it will hit the end of the result set.
or just call closeCursor()
*if you look at the source for closeCursor(), the default implementation literally just fetches the rows and discards them until it reaches the end. It's written in c obviously, but it more or less does this:
function closeCursor() {
while ($row = $stmt->fetch()) {}
$this->stmtFullyFetched = true;
}
Some db drivers may have a more efficient implementation that doesn't require them to fetch lots of rows that nobody cares about, but that's the default way PDO does it. Anyway...
Normally you don't have these problems when you use buffered queries. The reason is because with buffered queries, right after you execute them, PDO will automatically fully fetch the db results into php memory, so it does the "call fetch() until a fetch() fails" part for you, automatically. When you later call fetch() or fetchAll() yourself, it's fetching results from php memory, not from the db. So basically, the result set is immediately fully fetched when using buffered queries, so there's no opportunity to have more than 1 "result set in progress of being fetched" at the same time (because php is single threaded, so no chance of 2 queries running at the same time).
Given this:
$sql = "select * from test.a limit 1";
$stmt = $dbh->prepare($sql);
$stmt->execute(array());
Ways to fully fetch the result set (assuming you only want the first row):
$row = $stmt->fetch();
$stmt->closeCursor();
or
list($row) = $stmt->fetchAll(); //tricky
or
$row = $stmt->fetch();
while ($stmt->fetch()) {}
After struggling with this issue for days, I finally found that this worked for me:
$db = new PDO ($cnstring, $user, $pwd);
$db->setAttribute (PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, true);
This also happen if you are trying to fetch a non SELECT query (Eg - UPDATE/INSERT/ALTER/CREATE). Make sure to use fetch or fetchAll only for SELECT queries.
Possible Duplicate Answer/Question

PHP PDO mysql counting rows returned

There are a lot of questions on this and I have done a lot of research. However, I am still wondering if I am doing this right.
Here is my statement (I've simplified it):
try {
$stmt = $pdc_db->prepare("SELECT * FROM table WHERE color = :color");
$stmt->bindValue(':color', $selected_color);
$stmt->execute();
$color_query = $stmt->fetchAll();
} catch(PDOException $e) { catchMySQLerror($e->getMessage()); }
Now, I am using the following to see if this has returned any results:
if (count($color_query) > 0) {
This works, HOWEVER... the SELECT statement will only return one result. So now to access stuff in the results, I am using $color_query[0][colorname]. I know this is because I am using fetchAll(), but I really want to be using fetch()
But if I just use fetch(), I am losing the ability to do a count(), which is pretty simple to me. I know I can do a separate query and check the results of SELECT COUNT(*), but that seems like more work (setting two separate queries up for each)
There must be a way, using PDO in PHP with mySQL, to check if fetch() has returned a result?
$stmt->rowCount() after the execute(), but doesn't work with all databases... try it with MySQL and see what you get.
You can do it with fecth, fecth will return false if no results returns.
if ($row = $stmt->fetch()) {
//get the first row of the result.
//....
}

Categories