prepared statement where value is in array - php

In a php page, I have an array, similar to this:
$category = array(16, 22, 23);
Then I am doing a database query with a prepared statement. I would like to get all rows where the field category contains one of the values from that $category array and where price is lower than a value stored in the variable $price.
Among others I read the answers to this question and tried to use find_in_set() as described there (and at a lot of other places), but somehow I can't make it work within the prepared statement. I tried this:
/* database connection "$db" is established beforehand and works */
if($ps = $db->prepare("
SELECT id, product, category, price
FROM products
WHERE price <= ? and find_in_set(?, category)
ORDER BY id") {
$ps->bind_param("ds", $price, $category);
$ps->execute();
$ps->bind_result($id, $name, $cat, $pr);
while($ps->fetch()) {
/* ... echo the results ..... */
}
$ps->free_result();
$ps->close();
}
But I get an empty result.
If I try to use "dd" or "di" instead of "ds" in the bind_param() line, I do get results, but the wrong ones - I get all rows with category 1.
I also tried to use category IN ? instead of find_in_set(?, category), but that won't work either.
What can I do to make that work? Any help appreciated!

Two issues:
The list should be passed as second argument to find_in_set, so it should be:
find_in_set(category, ?)
That argument should be of type string (comma separated values). So first convert your array to such a string with implode:
$csv = implode(",", $category);
Code:
if($ps = $db->prepare("
SELECT id, product, category, price
FROM products
WHERE price <= ? and find_in_set(category, ?)
ORDER BY id") {
$csv = implode(",", $category);
$ps->bind_param("ds", $price, $csv);
$ps->execute();
$ps->bind_result($id, $name, $cat, $pr);
while($ps->fetch()) {
/* ... echo the results ..... */
}
$ps->free_result();
$ps->close();
}

If you want to find values where $category belongs to a certain set try using IN. Just a note you cannot pass an array into a string like you have above.
Also don't forget to convert your array to a CSV string using implode
$category = array(16, 22, 23);
$cat_str = implode(",",$category); //16,22,23
$ps = $db->prepare("
SELECT id, product, category, price
FROM products
WHERE price <= ? and category IN (?)
ORDER BY id") {
$ps->bind_param("ds", $price, $cat_str);

if i tried the same case , then i would probably have done it like this
SELECT id, product, category, price
FROM products
WHERE category = '16' || category = '22' || category = '23' and price < $price`
i am assuming your $category array variable is fixed , it's not dynamically appending value .
I answered only your query part . i'd hope you have php coding convention idea rather than putting the entire statement in the if statement .
if still has anything to ask about , please go ahead

Related

PDO fetch me a fake result

I'm working on a function that compare two price.
I have a table called 'PRODUCT' that has 3 column: ID, REFERENCE, PRICE.
I get a price from a FORM that i will compare with the column PRICE. If the number that i get with the form, is different by PRICE from the table, i want get the REFERENCE. So i work in this way:
$pdo = new PDO ("mysql:host=$hostname;dbname=$dbname", $user, $pass);
$sql = "SELECT count(1) as NB
FROM ww_ps_product
WHERE reference = :reference AND SUBSTR(wholesale_price , 1, INSTR(wholesale_price ,'.')+2) != :price" ;
$stmt = $pdo->prepare($sql);
$stmt->bindValue(':reference', **$referenza**, PDO::PARAM_STR);
$stmt->bindValue(':price', **$prezzoAggiornato**);
$stmt->execute();
$product = $stmt->fetch(PDO::FETCH_ASSOC);
The value that i get from the form : $referenza is FIN 260482300000 and the $prezzoAggiornato is 6.90 . Normalli, in my $product, i should have 0 but i get 1.
This data are store in DB with the same values:
When i go to compare with my function, i get NB = 1 but that's is impossible. If i check with the same values in phpMyAdmin i get NB = 0.
There is something wrong in my code?

Multiple Where statements in MySQL

I have a SQL statement where I want the WHERE part to be dynamically filled by the calling function. The function that calls the statement should be able to pass one or more parameters with 'OR'. Unfortunately, the statement always takes only the first entry.
$category = 'cat1' OR 'cat2' OR 'cat3';
$result = getEntries($category, $mysqli);
function getEntries($category, $mysqli){
$queryData = $mysqli->prepare("SELECT * FROM items WHERE category = ?");
$queryData->bind_param("s", $category);
$queryData->execute();
$queryData = $queryData->get_result();
return $queryData;
}
I only get results for "cat1"
Thanks for your help
You are using OR operator to assign a variable, which will assign one value at a time, if you want the number of categories dynamically then you can modify your code like below:
$categories = ['cat1','cat2','cat3'];
$result = getEntries($categories, $mysqli);
function getEntries($categories, $mysqli){
$plcs = implode(',',array_fill(0,count($categories)-1, "?");
$queryData = $mysqli->prepare("SELECT * FROM items WHERE category IN ({$plcs})");
$queryData->bind_param(str_repeat("s", count($categories)), ...$categories);
$queryData->execute();
return $queryData->get_result();
}
wrong assignment .
$category = 'cat1' OR 'cat2' OR 'cat3';
correct it . See the basics of bind param from below :
https://www.php.net/manual/en/mysqli-stmt.bind-param.php
And multiple where statment can be like this :
SELECT * FROM items WHERE category in ("cat1","cat2","cat3")
also you can use following when your database has extra space or want to match anything containing cat1,cat2,cat3:
SELECT * FROM items WHERE category like '%cat1%' or category like '%cat2%' or
category like '%cat3%'

MySQL return rows where column contains categories defined by array (and add weight to the results)

In my app, the user can type in an indefinite amount of categories to search by. Once the user hits submit, I am using AJAX to call my PHP script to query my DB and return the results that match what the user defined for the categories.
My category column is separated as so for each row: "blue,red,yellow,green" etc.
I have two questions:
How can I pass an array to MySQL (like so: [blue,yellow,green]) and then search for each term in the categories column? If at-least one category is found, it should return that row.
Can MySQL add weight to a row that has more of the categories that the user typed in, therefor putting it further to the top of the returned results? If MySQL cannot do this, what would be the best way to do this with PHP?
Thanks for taking the time and looking at my issue.
For the part 1 you can use the function below:
<?php
function createquery($dataarray){
$query="select * from table where ";
$loop=1;
foreach($dataarray as $data)
{
$query.="col='$data'";
if(count($dataarray)<$loop-1){
$query.=' or ';
}
$loop++;
}
return $query;
}
?>
This will return the long query.
use this some like this:
mysql_query("select * from table where category in (".implode($yourarray,',').")");
1)
Arrays are not passed to a MySQL database. What's past is a query which is a string that tells the database what action you want to preform. An example would be: SELECT * FROM myTable WHERE id = 1.
Since you are trying to use the values inside your array to search in the database, you could preform a foreach loop to create a valid SQL command with all those columns in PHP, and then send that command / query to the database. For example:
$array = array('blue', 'red', 'yellow', 'green');
$sql = "SELECT ";
foreach ($array as $value)
{
$sql .= $value.", ";
}
$sql .= " FROM myTable WHERE id = 1";
IMPORTANT! It is highly recommended to used prepared statements and binding your parameters in order not to get hacked with sql injection!
2)
You are able to order the results you obtained in whichever way you like. An example of ordering your results would be as follows:
SELECT * FROM myTable WHERE SALARY > 2000 ORDER BY column1, column2 DESC

PDO select where

I am brand new to PHP and mysql and am trying something here. In my HTML, I have one form where I enter a mileage and it's passed on to the PHP code and converted to an integer. Then I want to take that and check against the database to isolate the record I want so I can do some computations. In other words, if the mileage entered (I save it in a veriable called $term) is less than or equal to a mileage in the table, I want to use the record that matches this criteria. For example, I enter 45 miles and the table has records at 40 miles and 50 miles, I want to pick the 50 mile level. If the user puts in 51, I want to use the 50 level. Things like that.
It connects to the database nicely but I'm not sure how to structure this at the foreach statement.
I have the following:
$term = (int)$_POST['term'];
try {
$dbh = new PDO("mysql:host=$hostname;dbname=ratetable", $username, $password);
/*** The SQL SELECT statement ***/
$sql = "SELECT * FROM rates WHERE mileage<=term";
foreach ($dbh->query($sql) as $row)
{
print $row['mileage'] .' - '. $row['ratepermile'] . '<br />';
}
/*** close the database connection ***/
$dbh = null;
}
When I do this, I get an invalid argument supplied foreach().
Then I started looking around and saw statements that look like this:
$stmt = $db->prepare( 'SELECT * FROM rates WHERE mileage<=:term' );
where the search parameter is passed and so on.
So now I'm confused about what the correct way is to select a single record in an ascending list of mileages in a database (the last matching record versus all that match) that satisfies a criteria or how to correctly structure the WHERE argument. Any suggestions?
Thank you for looking.
What you would need to do is use a WHERE clause in combination with ORDER BY and LIMIT clauses. For example to get the highest value that is less than or equal to a given search criteria you would do:
SELECT * FROM rates
WHERE mileage <= ?
ORDER BY mileage DESC
LIMIT 1
To get the lowest value that is greater than or equal to a given search value do:
SELECT * FROM rates
WHERE mileage >= ?
ORDER BY mileage ASC
LIMIT 1
As far as doing the actual PDO you would do something like this:
$stmt = $dbh->prepare('SELECT * FROM rates WHERE mileage <= ? ORDER BY mileage DESC LIMIT 1');
$stmt->execute(array($term));
$row_object = $stmt->fetchObject();
$sql = "SELECT * FROM rates WHERE mileage<=term";
What this means is select * from rates where the column mileage <= the column term. I do not think you have the column term as that should be a parameter.
You are right to take a look at parameters. The code should be something like:
$term = 150;
$sth = $db->prepare('SELECT * FROM rates WHERE mileage<=?');
$sth->execute(array($term));
To get only one of the records you should order by a column and get only the LIMIT 1
$term = 150;
$sth = $db->prepare('SELECT * FROM rates WHERE mileage<=? ORDER BY mileage DESC LIMIT 1');
$sth->execute(array($term));
Because you only want 1 row you can just do a $result=$sth->fetchColumn(); instead of the foreach.

Filtering PDO SQL Queries

I'm using PDO method in my PHP page to implode two strings (in order to create a graph... long story!), but I don't know how to filter them. The table structure in MySQL is like this:
Column Name:
item (the name of the item being voted on);
nvote (the number of votes this item has received);
date (the dates of the votes)
This is what I have so far:
$stmt1 = $db->prepare("SELECT date FROM vote");
$stmt1->execute();
$stmt2 = $db->prepare("SELECT nvote FROM vote");
$stmt2->execute();
$line1 = implode( ',', $stmt1->fetchAll (PDO::FETCH_COLUMN) );
$line2 = implode( ',', $stmt2->fetchAll (PDO::FETCH_COLUMN) );
(Line1 creates the x-axis of my graph, line2 creates the y-axis)
This works very well to generate the strings for my graph.
How can I filter these so that name of the item being voted on (in the "item" column") is filtered by a var (in this case, $nameofitem)? I can't seem to get it to work.
$params = array(':value' => 'Hello World');
$stmt1 = $db->prepare("SELECT date FROM vote WHERE item = :value ORDER BY date");
$stmt1->execute($params);
$stmt2 = $db->prepare("SELECT nvote FROM vote WHERE item = :value ORDER BY date");
$stmt2->execute($params);
$line1 = implode( ',', $stmt1->fetchAll (PDO::FETCH_COLUMN) );
$line2 = implode( ',', $stmt2->fetchAll (PDO::FETCH_COLUMN) );
The key is adding a WHERE condition in the SQL query with a parameter that is bound by execute when passed an array.
Note that I also added an order statement for you as there is no guarantee of the result ordering without it, meaning the points you saw on the graph could have been associated with the wrong point. Date might not be the best choice, use a unique key if you can. Alternatively, you could fetch everything in a single query and build your lists with post-processing.

Categories