SELECT IN statement doesn't work properly - php

I'm trying to select with IN from mysql.
I have this query: SELECT id, name FROM country WHERE id IN (2,1)
If I run it from phpmyadmin I get two rows, but when I want to do it in a function I get just one row
This is my function
function search($res) {
global $pdo;
$arr = [$res];
$in = str_repeat('?,', count($arr) - 1) . '?';
$sql = "SELECT id, name FROM country WHERE id IN ($in)";
$stmt = $pdo->prepare($sql);
$stmt->execute($arr);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
return $stmt->rowCount();
}
What am I missing?
The problem seems to come from count($arr), gets back as 1.

Found the problem
$arr = [$res] -> $arr = explode(',', $res)
I was getting all the elements of the array as the first and only element, I had to explode by comma to get the actual array.

Related

PDO: Delete query only deleting entries of first value in IN statement [duplicate]

I found this code on SO, which is great for using PDO and the IN() statement together.
$values = explode(',', $values) ; # 1,4,7
$placeholders = rtrim(str_repeat('?, ', count($values)), ', ') ;
$query = "SELECT * FROM table WHERE id IN ($placeholders)";
$stm = $db->prepare($query) ;
$stm->execute($values) ;
However, how can I mix in another addition to the query so the query looks like this:
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
$stm = $db->prepare($query) ;
$stm->execute(array($values,$product)) ; //error happens when adding product placeholder
I thought this would work but I get:
Warning: PDOStatement::execute() [pdostatement.execute]: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens in line 3 (the $stm line)
Any idea how to get this to behave as intended?
UPDATED execute to array, still not working..
Solution
This should work, if $values is an array:
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
$stm->execute(array_merge($values, array($product)));
Explanation
execute() expects one parameter - in this case an array - to be provided. By adding array_merge($values, array($product)) you create one array with $product added at the end, so the query should work correctly.
See the demo here: http://ideone.com/RcClX
$stm->execute($values,$product) ; //error happens when adding product placeholder
The problem here is that execute needs a single array. You can't pass multiple arrays, and worse, you can't nest arrays.
We already have a perfectly good $values array, so let's reuse it after you create the placeholder string.
$values = explode(',', $values) ; # 1,4,7
$placeholders = rtrim(str_repeat('?, ', count($values)), ', ') ;
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
// New!
$values[] = $product;
$stm = $db->prepare($query);
$stm->execute($values);
And an other solution can be (if you like the :param_name = $value way, as me):
$params = array(
':product' => $product
);
$_in_params = array();
foreach ( $_in_values as $idx_in => $value_in)
{
$_in_params[] = ':param_in_'.$idx_in;
$params[':param_in_'.$idx_in] = $value_in;
}
$query .= "SELECT * FROM table WHERE id IN (".join(',',$_in_params).") AND product=:product";
I'm not sure if this is the best and the most optimal solution, but it's a little bit more human readable :) And it can be helpful if you have a big an complicated query and you want to debug it
(I'm curious if someone have a good argument why NOT to do in this way)
You forgot to prepare it ^_^
$query = "SELECT * FROM table WHERE id IN ($placeholders) AND product=?";
$stm = $db->prepare($query) ;
$stm->execute($values,$product) ; //p00f
And aside from that execute() should only have one parameter
So the above won't work AT ALL!
See the DOCs
Placeholders version if you need it
$values = [1, 4, 7, 8];
$placeholders = preg_filter('/^/', ':prefix_', array_keys($values)));
$query = 'SELECT * FROM table WHERE id IN ( '. implode(', ', $placeholders) . ')';
$stmt = $db->prepare($query);
if (count($values) > 0) {
foreach ($values as $key => $current_value) {
$stmt->bindValue($placeholders[$key] , $current_value, PDO::PARAM_STR);
}
}
$stmt->execute();
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);

Select from database where a column equals any value in a variable

My database looks like this:
I have a variable that looks like this:
$following = "John, Sarah";
I would like to get the rows where the column 'username' is in the variable $following (in this case, John and Sarah). To do this, I had a look at the answer https://stackoverflow.com/a/1356018/5798798 which suggested I use IN in my query, which I have attempted:
$following = "John, Sarah";
$stmt = $con->prepare("SELECT * FROM events WHERE username IN ('$following')");
$stmt->execute();
while($row = $stmt->fetch()) {
echo $row['eventtype'];
}
The problem is that the query is returning no data. My desired result would be:
spoke walked
From what I suggested in comments to use the following:
$following = "John, Sarah";
$following = explode(", ", $following);
$string = implode(", ", $following);
It ended up that I didn't include the quotes for the implode()'ing.
The final solution was to add the single quotes in the first parameter for the implode() function:
$following = implode("','",$following);
$following = join("', '", $following);
join no more returns an array. It is a string now.
You can use like this:
$in = str_repeat('?,', count($following ) - 1) . '?';
$stmt = $con->prepare("SELECT * FROM events WHERE username IN ($in)");
$stm->execute($following);
with out using join you directly implode array by the following way
$stmt = $con->prepare('SELECT * FROM events WHERE username IN ("'. implode('","', $following).'")');
$stmt->execute();
while($row = $stmt->fetch()) {
echo $row['eventtype'];
}
Note: $following always should be in array

PHP reverse stored procedures function?

lets say I have the following query in a variable:
$sql = "select id, salary, fname, lname from users where id = ? and salary > ?";
and an array like this:
$params = array (
0 => '38765',
1 => '4000');
I was wondering if there is a simple of built in PHP to do this to replace the "?" in the query to get the following result:
"select id, salary, fname, lname from users where id = '38765' and salary > '4000' ";
the query won't be executed by the way, this more of a sting manipulation question than a sql one.
this is as close as I got but it looks like PHP might have something built it for it:
foreach ($params as $param){
$pos = strpos($sql, '?');
$sql = substr_replace($sql, "'".$param."'", $pos, 1);
}
Yes, there is.
See this code example from php.net
$stmt = $dbh->prepare("SELECT * FROM REGISTRY where name = ?");
if ($stmt->execute(array($_GET['name']))) {
while ($row = $stmt->fetch()) {
print_r($row);
}
}
http://php.net/manual/en/pdo.prepared-statements.php#example-1016
But this variant requires that you work with PDO.
See this link for more details:
http://php.net/manual/en/book.pdo.php

SQLITE build query string from values passed

Hi have a function that gets passed strings via the below;
getFilterResults($id, $limit, $misc);
and in my function i connect to SQLite DB and build a query based on the values passed through, like so;
function getFilterResults($id, $limit, $misc) {
$dbConnect = new SQLite3(database);
if(!empty($limit) && !empty($id) && !empty($misc)){
$buildString = ('SELECT * FROM fields ORDER BY id DESC');
}else{
//no params filters arrived so dont filter - aka get all results
$buildString = ("SELECT * FROM fields ORDER BY id DESC");
}
$query = $dbConnect->query($buildString);
//...
}
Issue is how do I build the query if some of the values are empty and I have to decide which value uses/starts of the 'WHERE' query..obviously the first value return that is not null starts of the 'WHERE'..
I can see the long way would be to loop through each one and build - once the first value found that is not null and kick off from there but that seems unpractical and not good practice.
//check if limit set..
if($limit) {
$doLimit = 'LIMIT '.$limit.'';
}
WHERE 'id = '.id.' AND misc = '.$misc.' '.$doLimit.'
Your function taking in ($id, $limit, $misc) really prevents you from being able to do anything else than what you already are... I would recommend using prepared statements though
// Stores values for a prepared statement
$values = [];
$sqlite = new SQLite3(/* ... */);
$query = 'SELECT * FROM fields WHERE id = ? AND misc = ? ORDER BY id DESC';
$values[] = $id;
$values[] = $misc;
if ($limit) {
$query .= ' LIMIT ?';
$values[] = $limit;
}
// Use prepare and let SQLite3 escape the values for you
$stmt = $sqlite->prepare($query);
foreach ($values as $idx => $val) {
$stmt->bindValue($idx, $val);
}
$result = $stmt->execute();

How to use PDO prepared statements with IN clause? [duplicate]

This question already has answers here:
Can I bind an array to an IN() condition in a PDO query?
(23 answers)
Closed 1 year ago.
I stored some data in a field inside MySQL in this format: 1,5,9,4
I named this field related. Now I want to use this field inside an IN clause with PDO. I stored that field contents in $related variabe. This is my next codes:
$sql = "SELECT id,title,pic1 FROM tbl_products WHERE id IN (?) LIMIT 4";
$q = $db->prepare($sql);
$q->execute(array($related));
echo $q->rowCount();
But after executing this code, I can fetch only one record whereas I have to fetch 4 records (1,5,9,4). What did I do wrong?
using named place holders
$values = array(":val1"=>"value1", ":val2"=>"value2", ":val2"=>"value3");
$statement = 'SELECT * FROM <table> WHERE `column` in(:'.implode(', :',array_keys($values)).')';
using ??
$values = array("value1", "value2", "value3");
$statement = 'SELECT * FROM <table> WHERE `column` in('.trim(str_repeat(', ?', count($values)), ', ').')';
You need as many ? placeholders as your "IN" values.
So:
$related = array(1,2,3); // your "IN" values
$sql = "SELECT id,title,pic1 FROM tbl_products WHERE id IN (";
$questionmarks = "";
for($i=0;$i<count($related);$i++)
{
$questionmarks .= "?,";
}
$sql .= trim($questionmarks,",");
$sql .= ") LIMIT 3;";
// echo $sql; // outputs: SELECT id,title,pic1 FROM tbl_products WHERE id IN (?,?,?) LIMIT 3;
$q = $db->prepare($sql);
$q->execute($related); // edited this line no need to array($related), since $related is already an array
echo $q->rowCount();
https://3v4l.org/No4h1
(also if you want 4 records returned get rid of the LIMIT 3)
More elegantly you can use str_repeat to append your placeholders like this:
$related = array(1,2,3); // your "IN" values
$sql = "SELECT id,title,pic1 FROM tbl_products WHERE id IN (";
$sql .= trim(str_repeat("?,",count($related)),",");
$sql .= ") LIMIT 3;";
// echo $sql; // outputs: SELECT id,title,pic1 FROM tbl_products WHERE id IN (?,?,?) LIMIT 3;
$q = $db->prepare($sql);
$q->execute($related); // edited this line no need to array($related), since $related is already an array
echo $q->rowCount();
https://3v4l.org/qot2k
Also, by reading again your question i can guess that your $related variable is just a string with value comma-separated numbers like 1,40,6,99. If that's the case you need to make it an array. do: $related = explode($related,","); to make it an array of numbers. Then in your execute method pass $related as-is.

Categories