Joshua Kast
Joshua Kast

Reputation: 340

Iterating over results of PDO query

I want to run a query using PDO, based on data in the URL paramater (yes, I know that this is prone to attacks, but its internal code for a utility).

$user = 'USER';
$pass = 'PASSWORD';
$dsn = 'mysql:dbname=PRODUCTS;host=HOST'; 

try {
    $productDB = new PDO($dsn, $user, $pass); 
    $productDB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
catch(PDOException $e) {
    $msg = 'PDO ERROR' . $e->getFile() . ' L.' . $e->getLine() . ' : ' . $e->getMessage();
    die($msg);
}
if(isset($_GET['cat'])) 
{
    $cat = $_GET['cat'];
    print "cat = $cat <br>";
    $products = $productDB->prepare('SELECT * FROM products WHERE cat_id LIKE ?');
    $products->execute(array($cat));
    $rows = $products->rowCount();
    print "$rows rows returned";
?>
<table border="1">
<tr>
    <td>product_id</td>
    <td>product_name</td>
</tr>
<?php
foreach ($products->fetchAll() as $row) {
    $id = $row['product_id'];
    $product_name = $row['product_name'];
    print "<tr>";
    print "<th scope=\"row\"><b>$id</b></th>";
    print "<td> $product_name </td>";
    print "<tr>";
    }
print "</table>";
}
?>

When I run this code, it prints the correct number of rows depending on the query, but does not populate the table.

I have also tried replacing the prepare and execute lines with:

$products = $productDB->query("SELECT * FROM products WHERE cat_id LIKE $cat");

Which returns the correct row count, but doesn't otherwise help.

And finally, I've tried replacing the foreach line with something like:

$rows = $products->fetchAll();
foreach ($rows as $row) {

My attempts to do the same with a fixed query all work fine, but I am having trouble working out how to place a variable element in a query, and then iterate over the results.

Upvotes: 5

Views: 714

Answers (2)

Cyril N.
Cyril N.

Reputation: 39859

Try this (If I understood correctly) :

$products = $productDB->prepare("SELECT * FROM products WHERE cat_id LIKE :cat");

// Now, you can either do this :
$products->bindParam('cat', '%'.$cat.'%');
$products->execute();

// or you can call execute with an associative array of your parameterized query.
$products->execute(array('cat' => '%'.$cat.'%'));

// Then, get all the results like this :
$rows = $products->fetchAll();
foreach ($rows as $row) {
    // Do work here ..
}

// Or, like this :
while ($row = $products->fetch(PDO::FETCH_ASSOC)) {
    // Do work here ..
}

I personaly prefer the while, because you don't fetch the whole query in one var, reducing the amount of memory needed.

I also recommend you to use the FETCH_* parameter, to get only the kind of array you want.

By the way, you need to know that rowCount should not be used to count the rows returned by a SELECT. As said by php.net :

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.

Upvotes: 2

Adam Hopkinson
Adam Hopkinson

Reputation: 28795

You're not doing anything to store the result:

$products->execute(array($cat));

needs to go in a variable:

$result = $products->execute(array($cat));

Then, instead of calling $products->fetchAll(), use $results->fetchAll():

foreach ($result->fetchAll() as $row)

I find it easier to use a $query variable (for prepare, etc) and then get the result into something like $result or $product. Makes the code a bit easier to read.

Upvotes: 3

Related Questions