PDO MySQL prepared statement with optional where statements - php

I am working on a query that is submitted from a form with a variety of search options that could or could not be included in my query. Is there a better way to do this dynamically as this doesn't seem to work?
I keep getting error Fatal error: Call to a member function fetchAll() on boolean. I know there is a lot going on here and I didn't want to put a ton of code to read through. So to make a long story short, when I echo out $sql my select statement looks good, but no matter what I do I keep getting the same error which tells me there is something wrong with the statement. Is this approach even workable or do I need to use another method? If so what is a better approach?
$sql = "SELECT DISTINCT mt.id, mt.name, mt.phone
FROM main_table mt
LEFT JOIN jnct_tbl_srvstate st ON mt.id = st.mt_id
LEFT JOIN jnct_tbl_equip eq on mt.id = eq.mt_id
LEFT JOIN jnct_tbl_accessory ac ON mt.id = ac.mt_id
LEFT JOIN tbl_car c ON mt.id = c.mt_id
WHERE mt.id = c.id";
if($state_array_count != 0){
$sql.= " AND srvstate_id IN ($st_holders)";
}
if($equip_array_count != 0){
$sql.= " AND equip_id IN ($eq_holders)";
}
if($accessory_array_count != 0){
$sql.= " AND accessory_id IN ($ac_holders)";
$sql.= " ORDER BY mt.id";
$query = $db->prepare($sql);
Incorporating the if statements above is what I really need help with.
if($state_array_count != 0){
foreach($state_array as $st_placeholder => $st_value) {
if($st_value != '') {
$st_placeholder = ":$st_placeholder";
$query->bindValue($st_placeholder, $st_value);
}
}
}
if($equip_array_count != 0){
if($eq_value != '') {
foreach($equip_array as $eq_placeholder => $eq_value) {
$eq_placeholder = ":$eq_placeholder";
$query->bindValue($eq_placeholder, $eq_value);
}
}
}
if($accessory_array_count != 0){
foreach($accessory_array as $ac_placeholder => $ac_value) {
if($ac_value != '') {
$ac_placeholder = ":$ac_placeholder";
$query->bindValue($ac_placeholder, $ac_value);
}
}
}
$results = $query->execute();
$rs = $results->fetchAll(PDO::FETCH_ASSOC);

The execute() method does not return a results object. It returns a boolean, true or false.
fetchAll() is a method of the PDOStatement object. Here's an example:
$sth = $dbh->prepare($sql);
$sth->execute();
$result = $sth->fetchAll();

Related

How to get count of the sql search query?

How to get count of the sql search query
$u = new user();
$sql = "SELECT a.id FROM `accounts` AS a LEFT JOIN `users` AS u ON a.id = u.id WHERE a.id IS NOT NULL ";
$gender = $this->input->post('gender');
if($gender != NULL)
{
$sql .= "AND u.gender = '".$gender."' ";
}
$u->query($sql);
How to get count of the query results in $u->query($sql); .I need to set a validation on it. If the query results count is 0 , i need to set a message. Im using PHP Codeigniter ,datamapper library.
Thank you!!!
Just using count() function like this
...
$result = $u->query($sql);
$total_data = count($result);
if($u->exists())
{
echo "Found" // Do something
}
else
{
echo "Nothing found" //Do something
}
$result = $this->db->get();
For Codeigniter use $count = $result->num_rows(); // HERE IS YOUR COUNT
For OOP PHP use $count = $result->num_rows;

Counting rows, and executing while loop only if more than 0 rows with prepared PDO

I am trying to do a while loop with a prepared PDO statement, but I only want it to execute if there are any rows. Currently I am using this, but it seems to be missing the first result, presumably because its moving the pointer.
What is the right way to do this?
$stmt = $pdo->prepare('SELECT * FROM products p
INNER JOIN products_to_categories c
ON p.products_id = c.products_id
WHERE c.categories_id = ?
AND products_status=?
ORDER BY p.products_sort_order,p.products_name');
$stmt->execute([$categories_id,1]);
if(($category_row = $stmt->fetch(PDO::FETCH_ASSOC)) != null) {
$no_results = count($stmt->fetch(PDO::FETCH_ASSOC));
while ($products_row = $stmt->fetch(PDO::FETCH_ASSOC)) {
// show row info
}
}
What about something like:
$stmt = $pdo->prepare('SELECT * FROM products p INNER JOIN products_to_categories c ON p.products_id = c.products_id
WHERE c.categories_id = ? AND products_status=? ORDER BY p.products_sort_order,p.products_name');
$stmt->execute([$categories_id,1]);
$products_row="some_random_string";
while ($products_row = $stmt->fetch(PDO::FETCH_ASSOC) && $product_row!="some_random_string" && $product_row!=false) {
// show row info
}
Since you talked about row count,
$result = $con->prepare("SELECT count(*) FROM `products`");
$result->execute();
$number_of_rows = $result->fetchColumn();
You do not need to check the row count. Simply rewrite:
$stmt = $pdo->prepare('...');
$stmt->execute([$categories_id, 1]);
$rows = 0;
while ($products_row = $stmt->fetch(PDO::FETCH_ASSOC) {
// You can increment $rows only if some other condition is met if you want
$rows++;
// show row info
}
switch ($rows) {
case 0:
// No rows were retrieved.
// run the 'different function' you mentioned in the comments
break;
case 24:
print "There are two dozen rows in your results";
break;
}
As requested, the while loop will never execute if there are no results. And if there are, it will loop every one of them.

How can I count the total number of duplicate values between 2 tables on an inner join

I have the following query
SELECT fixtures.Fixture_ID, fixtures.Home_Score,
fixtures.Away_Score, predict.Fixture_ID, predict.pHome_Score, predict.pAway_Score
FROM fixtures INNER JOIN predict
ON fixtures.Fixture_ID=predict.Fixture_ID
I want to count the number of times the following condition is met
fixtures.Home_Score=predict.pHome_Score
AND fixtures.Away_Score=predict.pAway_Score
AND fixtures.Fixture_ID=predict.Fixture_ID
I tried using a 'COUNT()' then 'Having count()>1' but cant get the syntax to work
I have also tried to count the number of times the if condition is met in the following php. I'm not sure if this is possible, so I thought the count might have to done within as SQL statement
<?php
$current = $user->data()->id;
$sql2 = "SELECT fixtures.Home_team, fixtures.Away_Team, fixtures.Home_Score, fixtures.Away_Score, predict.pHome_Score, predict.pAway_Score FROM fixtures
INNER JOIN predict
ON fixtures.Fixture_ID=predict.Fixture_ID WHERE predict.id='".$current."'";
echo "The number of detected predictions:", '<br>';
$predictions = DB::getInstance()->query($sql2);
foreach ($predictions->results() as $rows) {
$rows= get_object_vars($rows);
$num_rows= $predictions->count();
}
for($count=0;$count<$num_rows;$count++){
$r_home_score = $predictions->results()[$count]->Home_Score;
$p_home_score = $predictions->results()[$count]->pHome_Score;
$r_away_score = $predictions->results()[$count]->Away_Score;
$p_away_score = $predictions->results()[$count]->pAway_Score;
$p=0;
if($r_home_score==$p_home_score&&$r_away_score==$p_away_score){
$p++;
echo $p;
}
}
The output is:
The number of detected predictions:
111111
I want to output 6
If you just want a single count returned from the database, you could just do a query like this:
SELECT COUNT(*) AS mycount
FROM fixtures f
JOIN predict p
ON p.Fixture_ID = f.Fixture_ID
AND p.pHome_Score = f.Home_Score
AND p.pAway_Score = f.Away_Score
FOLLOWUP
$dbh = DB::getInstance();
$sql = "SELECT COUNT(*) AS mycount
FROM fixtures f
JOIN predict p
ON p.Fixture_ID = f.Fixture_ID
AND p.pHome_Score = f.Home_Score
AND p.pAway_Score = f.Away_Score
WHERE p.id = ?";
if ($sth = $dbh->prepare($sql)) {
$sth->bindParam(1, $current, PDO::PARAM_INT);
if ($sth->execute()) {
if ($row = $sth->fetch(PDO::FETCH_ASSOC)) {
echo $row['mycount'];
} else {
// this should never happen with a COUNT(*) query
echo "query returned 0 rows";
}
} else {
echo "PDO error on execute: ";
print_r($dbh->errorInfo());
} else {
echo "PDO error on prepare: ";
print_r($dbh->errorInfo());
}

Model PHP SQL IF Statement Not Working

I am unsur why the below statement is not working basically in a nutshell I am wanting it to run the $result statement if only the $product_id is not found in the $images table. Is it is found I would like it to then run the inner statement.
Both statements do work via phpMyAdmin and the $result statement works when just using $this->db->query
Code:
public function product_delete($product_id)
{
$table = $this->_table_products;
$images = $this->_table_product_images;
$result = $this->db->query("SELECT `id` FROM $table WHERE $table.id ='$product_id'");
if(mysqli_num_rows($result) !== 0)
{
$this->db->query("DELETE FROM $table WHERE $table.id = '$product_id'");
}else{
$this->db->query("DELETE FROM $table INNER JOIN $images ON $table.id = $images.product_id WHERE $images.id = $product_id");
}
}
You have to use {} around variable name in query. Also use != instead of !==
$result = $this->db->query("SELECT `id` FROM {$table} WHERE {$table}.id ='$product_id'");
if(mysqli_num_rows($result) != 0)
{
$this->db->query("DELETE FROM {$table} WHERE {$table}.id = '$product_id'");
}else{
$this->db->query("DELETE FROM {$table} INNER JOIN {$images} ON {$table}.id = {$table}.product_id WHERE {$images}.id = $product_id");
}
Change !== to !=
if(mysqli_num_rows($result) != 0)
{
$this->db->query("DELETE FROM $table WHERE $table.id = '$product_id'");
}
else
{
$this->db->query("DELETE FROM $table INNER JOIN $images ON $table.id = $images.product_id WHERE $images.id = $product_id");
}
If you want to check the images table, you should query the table ${images}, not ${table}. Also, if you are only interested in finding out how many matching rows there are, it's best to use the COUNT() function in MySQL. That way you always get one row instead of potentially 100,000s. Using the function mysqli_num_rows() has the disadvantage that you're loosing the flexibility that the CodeIgniter database class introduces.
So your code should be something like
$result = $this->db->query("SELECT COUNT(*) `cnt` FROM ${images} WHERE ${images}.product_id ='$product_id'");
$row = $result->row();
if($row['cnt'] != 0) {
// found something
If the variable name is unclear in a string, you can use brackets to tell PHP what you want. "${foo}bar" means that the variable is $foo and bar is just some string to append to the variable content. It also helps to improve readability. And I changed !== to != because I'm not familiar enough with CI and I do not know if the value will be an integer or the string representation of an integer.

Problems with using PDO to perform an advanced search query

I have the following code and all of the search functions work except for the title field. So I can search by genre, date, location etc... but not by title. When attempting to search by title nothing is returned at all. Can anyone help me with this?
Also, is there a more efficient way to count all the fields before limiting it for use in pagination later on?
$today = date("Y-m-d");
$query = "SELECT * FROM TABLE_NAME WHERE Date >= '$today'";
$bind = Array();
if ($_GET["Title"] && $_GET["Title"] != "") {
$query .= " and Title like %?%";
$bind['Title'] = $_GET['Title'];
}
if ($_GET["Genre"] && $_GET["Genre"] != "") {
$query .= " and Genre like %?%";
$bind['Genre'] = $_GET['Genre'];
}
if ($_GET["Location"] && $_GET["Location"] != "") {
$query .= " and Location like %?%";
$bind['Location'] = $_GET['Location'];
}
if ($_GET["Date"] && $_GET["Date"] != "") {
$query .= " and Date = %?%";
$bind['Date'] = $_GET['Date'];
}
$stmt = $db->prepare($query);
$stmt->execute($bind);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$num = count($rows);
$query .= " ORDER BY Date LIMIT $limit, 9";
$stmt = $db->prepare($query);
$stmt->execute($bind);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Edit: After everyone's help I thought I would post my now revised code for future reference. It turns out the other fields were not working, but instead due to the if statement all this was nested in the code simply wasn't being executed.
$today = date("Y-m-d");
$query = "SELECT * FROM TABLE_NAME WHERE Date >= '$today'";
$countq = "SELECT count(*) FROM TABLE_NAME WHERE Date >= '$today'";
$bind = Array();
if ($_GET["Title"] && $_GET["Title"] != "") {
$query .= " and Title like :title";
$countq .= " and Title like :title";
$bind[':title'] = "%{$_GET['Title']}%";
}
if ($_GET["Genre"] && $_GET["Genre"] != "") {
$query .= " and Genre like :genre";
$countq .= " and Genre like :genre";
$bind[':genre'] = "%{$_GET['Genre']}%";
}
if ($_GET["Location"] && $_GET["Location"] != "") {
$query .= " and Location like :loc";
$countq .= " and Location like :loc";
$bind[':loc'] = "%{$_GET['Location']}%";
}
if ($_GET["Date"] && $_GET["Date"] != "") {
$query .= " and Date = :date";
$countq .= " and Date = :date";
$bind[':date'] = "{$_GET['Date']}";
}
$stmt = $db->prepare($countq);
$stmt->execute($bind);
$rows = $stmt->fetchAll();
$num = count($rows);
$query .= " ORDER BY Date LIMIT $limit, 9";
$stmt = $db->prepare($query);
$stmt->execute($bind);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
all of the search functions work
With the given query it is not true
From PDO tag wiki:
placeholders cannot represent an arbitrary part of the query, but a complete data literal only. Neither part of literal, nor whatever complex expression or a syntax keyword can be substituted with prepared statement.
Prepare FULL literal first: $name = "%$name%"; and then bind it.
As for the "more" efficient method for pagination - yes, oh yes.
With your current way of counting data you don't actually need other queries. as you have ALL the data already and can paginate it as well.
But of course it will pollute all the memory soon. So, if you want to get a count of rows from database, get the very count: run the same query but instead of SELECT * make it "SELECT count(*)
There are not any errors returned, that's why I am so confused
From PDO tag wiki again:
It is essential to set ERRMODE_EXCEPTION as a connection option as it will let PDO throw exceptions on connection errors. And this mode is the only reliable way to handle PDO errors.

Categories