MySQL PDO Count Rows - Can I make this more efficient? - php

So, I've been learning PDO. So far, I am not at all impressed, honestly, due to the large amount of code needed to do small tasks. However, I am willing to convert nonetheless if I can get my code to be efficient and reusable.
My question is this: can I make this code any more efficient? By efficient, I mean both A) take up less lines, and B) run faster. I am worried that I am going about this all wrong. However, due to the lack of a num_rows() function, I can't think of a better way.
try
{
$sth = $dbh->prepare("SELECT * FROM table_name");
$sth->execute();
if (count($result = $sth->fetchAll()))
{
foreach ($result as $value)
{
// Rows returned! Loop through them.
}
}
else
{
// No rows returned!
}
}
catch (PDOException $e)
{
// Exception!
}
Is this written properly?

As far as my research has shown, no. There is no way to rewrite this code more concisely or logically--the way it stands is entirely optimized. :) It's easy to use, so that's definitely not a bad thing!

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
$sql = "SELECT COUNT(*) FROM table_name";
if ($res = $conn->query($sql))
{
/* Check the number of rows that match the SELECT statement */
$res->fetchColumn(); //This will give you the number of rows selected//
}
Make a general function that does that, and all you need to do is send a select count based on your needs. You can make in more general by dividing the $select to more variables.
function countRows($select)
{
if ($res = $conn->query($select))
{
/* Check the number of rows that match the SELECT statement */
return $res->fetchColumn(); //This will give you the number of rows selected//
}
}

No, you need to use PDO's rowCount method.
try
{
$sth = $dbh->prepare("SELECT * FROM table_name");
$sth->execute();
if ($sth->rowCount() > 0)
{
while ($result = $sth->fetch())
{
// Rows returned! Loop through them.
}
}
else
{
// No rows returned!
}
}
catch (PDOException $e)
{
// Exception!
}

Related

How to return number rows affected on multiple inserts with Mysqli Php?

I have a function which inserts multiple rows using the MySqli library with prepared statements. The inserts works great, the problem is the build in $stmt->affected_rows method always returns the number of affected rows as 1.
Now to move around the affected row issue I created a counter which counts each executed statement. This solution is accurate. But I enjoy using built in methods and functions, so why is the $stmt->affected_rows always returning one, even though I inserted multiple rows? Is my code defective in some way or form? Maybe there is a pure Sql solution.
Here is my code:
try {
$query = "INSERT INTO dryenrolltb(enroll_id,id_entity,bin_type,tara_weight,dtetime_created,enrollprint_status) VALUES(?,?,?,?,?,?)";
$stmt = $db->prepare($query);
$stmt->bind_param('iiidsi', $enroll,$ent,$bin,$tara,$dte_create,$enr_status);
$result['rows']['rowerrors'] = array();
$result['rows']['rowsaffected'] = [];
$cnt = 0;
foreach ($arr as $value) {
$enroll = $value['enroll'];
$ent = $value['entid'];
$bin = $value['bin_t'];
$tara = $value['tara'];
$dte_create = $value['dtecreat'];
$enr_status = $value['enr_status'];
if($stmt->execute()) {
$cnt++;
} else {
array_push($result['rows']['rowerrors'],$value['enroll']);
}
}
if ($stmt->affected_rows > 0) {
echo "Affectionately yours";
array_push($result['rows']['rowsaffected'], $stmt->affected_rows);
array_push($result['rows']['rowsaffected'], $cnt);
return $result;
} else {
return false;
}
} catch (Exception $e) {
echo "Danger exception caught";
return false;
}
Can someone please give me a clue on why the $stmt->affected_rows always returns one on multiple inserts?
No. It seems like MySQLi statement class has no way of storing a running total of affected rows. After I thought about it, it makes total sense. Let me explain.
Every time you execute the statement it will affect a given number of rows. In your case you have a simple INSERT statement, which will add records one by one. Therefore, each time you call execute() the affected_rows value is one.
The query could be something different. For example INSERT INTO ... SELECT or UPDATE could affect multiple rows.
You could also have INSERT INTO ... ON DUPLICATE KEY UPDATE. If the key exists in DB, then you are not inserting anything. If the values are the same, you are not even updating anything. The affected rows, could be 0 or more.
The reason why it would be unwise for the statement to keep a running total of the affected rows is that each execution affects certain rows, irrespective of the previous executions. They could be even the same records. Consider the following example:
$stmt = $mysqli->prepare('UPDATE users SET username=? WHERE id=?');
$stmt->bind_param('si', $name, $id);
$id = 102;
$name = 'Affected rows 1';
$stmt->execute();
echo $stmt->affected_rows; // 1
$name = 'Affected rows 2';
$stmt->execute();
echo $stmt->affected_rows; // 1
Both update statements updated the same row. If mysqli kept a running total it would report 2 affected rows, but in reality only 1 row was changed. If the number was summed, you would be losing information.
So, for your simple scenario, it is fine to keep the total on your own, for example by summing up the $stmt->affected_rows after each execution. Anything more than that, it would probably not make much sense.

fetchColumn() not saving result to variable

So the query I am running can have 0, 1, or many results. I need to store the number of rows in a query to a variable. Using PDO I should be able to do that using the fetchColumn() method. But it is not givng ANY result. When I echo out $numrows I am getting nothing, not even a zero. I know it is probably something really small but I have been staring at this code for an hour now and I need a fresh set of eyes guys.
try {
$count = $db->prepare('SELECT COUNT(*) FROM location WHERE location.zip = :input');
$count->bindValue(':input', $input);
$numrows = $count->fetchColumn();
} catch (Exception $e) {
// Problem on MySQL PDO interaction - error message passed
$error = $e->getMessage();
}
You forgot to add just after binding the values, before fetchColumn():
$count->execute();

PHP: How do I get my IF statement to work with PDO select?

I want my below PDO select to work with the bottom two IF statements?
The first IF I just want to make sure there is no error.
The second IF I want to check how many rows it returns. I know that this number of rows == 0 will not work.
Is there a way to do that?
try {
$conn = new PDO('mysql:host=localhost;dbname=zs', 'zs', 'rlkj08sfSsdf');
$conn ->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e) {
echo $e->getMessage();
die();
}
$stmt = $conn->prepare("SELECT * FROM zip WHERE zip_code =:zip1");
$stmt->bindValue(':zip1', $_POST[zipcode], PDO::PARAM_INT);
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
if($rows = "") {
echo "<p><strong>There was a database error attempting to retrieve your ZIP Code.</strong></p>\n";
}
if(number of rows == 0) {
echo "<p><strong>No database match for provided ZIP Code.</strong> Please enter a new ZIP Code.</p>\n";
}
You're interested only in whether there are records containing a particular value. It makes no sense to select everything and count the records in PHP. It's a waste of resources. Imagine what happens if there's a million records.
Solution you're after is to simply ask your database about the COUNT of rows containing a particular value. Your code should be quite simple:
$stmt = $conn->prepare("SELECT COUNT(*) AS num_rows FROM zip WHERE zip_code = :zip");
$stmt->bindValue(':zip', $_POST['zipcode'], PDO::PARAM_INT);
$stmt->execute();
$count = (int)$stmt->fetchColumn();
if($count)
{
echo "Success";
}
else
{
echo "Bummer";
}
Notes:
if successful, the above query will always return 1 row with 1 column, named num_rows which will be 0 for no matching records or an integer larger than 0 if there are records. If you use MySQL native driver with PHP, PHP will correctly represent this value as integer internally. I deliberately put typecasting in, you can remove it (the (int) part) if you have MySQL ND.
if something goes wrong during query execution, an exception will be thrown. The snippet doesn't cover that. You correctly set PDO in exception mode, and along with using bindValue instead of bindParam, this implies you did your research right and you're using PDO correctly which means that error handling should be implemented easily by you in this particular case.

Check for PDO Results, If None Display Message, If Yes then Loop Through

Trying to find another simple answer but only finding complicated examples.
I'm trying to simply query a table, if there are results to display then loop through them, if there are not then display a message - unfortunately all examples I can find 'fetch' as part of the while loop, not before, so I'm trying to do:
$stm = $PdoObj->prepare("SELECT * FROM NEWS_articles");
$stm ->execute();
$results = $stm ->fetch();
if($results==null){
echo "<p>No dice, try other criteria</p>";
}else{
foreach($results as $row){
echo $row["articleName"];
}
}
The following question is close to what I'm trying to achive but was never answered satisfactorily: Is it possible to check if pdostatement::fetch() has results without iterating through a row?
You need not fetch() but fetchAll().
As mentioned by Your Common Sense use fetchAll. If there aren't any results, it will return an empty array:
$results = $stm->fetchAll();
if(empty($results))//or if(!$results) or if(count($results)==0) or if($results == array())
{
echo 'Nothing found';
}
else
{
foreach($results as $result)
{
//do stuff
}
}
The official method for getting how many rows have been returned is rowCount():
$stm->execute();
if($stm->rowCount() == 0)
{
echo 'Nothing found';
}
else
{
//do your stuff
}
Though this would not be necessary if you are already calling fetchAll as this result can be used to determine the size of the result set.
Instead of fetch() , use fetchAll().
fetchAll — Returns an array containing all of the result set rows

PHP MySQLi num_rows Always Returns 0

I have built a class which leverages the abilities of PHP's built-in MySQLi class, and it is intended to simplify database interaction. However, using an OOP approach, I am having a difficult time with the num_rows instance variable returning the correct number of rows after a query is run. Take a look at a snapshot of my class...
class Database {
//Connect to the database, all goes well ...
//Run a basic query on the database
public function query($query) {
//Run a query on the database an make sure is executed successfully
try {
//$this->connection->query uses MySQLi's built-in query method, not this one
if ($result = $this->connection->query($query, MYSQLI_USE_RESULT)) {
return $result;
} else {
$error = debug_backtrace();
throw new Exception(/* A long error message is thrown here */);
}
} catch (Exception $e) {
$this->connection->close();
die($e->getMessage());
}
}
//More methods, nothing of interest ...
}
Here is a sample usage:
$db = new Database();
$result = $db->query("SELECT * FROM `pages`"); //Contains at least one entry
echo $result->num_rows; //Returns "0"
exit;
How come this is not accurate? Other values from result object are accurate, such as "field_count".
Possible Bug: http://www.php.net/manual/en/mysqli-result.num-rows.php#104630
Code is from source above (Johan Abildskov):
$sql = "valid select statement that yields results";
if($result = mysqli-connection->query($sql, MYSQLI_USE_RESULT))
{
echo $result->num_rows; //zero
while($row = $result->fetch_row())
{
echo $result->num_rows; //incrementing by one each time
}
echo $result->num_rows; // Finally the total count
}
Could also validate with the Procedural style:
/* determine number of rows result set */
$row_cnt = mysqli_num_rows($result);
I had the same problem and found the solution was to put:
$result->store_result();
..after the execution of the $query and before
echo $result->num_rows;
This could be normal behavior when you disable buffering of the result rows with MYSQLI_USE_RESULT
Disabling the buffer means that it`s up to you to fetch, store and COUNT the rows.
You should use the default flag
$this->connection->query($query, MYSQLI_STORE_RESULT);
Equivalent of
$this->connection->query($query)

Categories