i will use "IN" operator with using parameter in prepare statement
but i can't do that
$hotel_list = "SELECT DISTINCT h.hotel_id, h.hotel_name, h.hotel_address, h.hotel_image
FROM type_feture tf
JOIN type t ON t.type_id = tf.type_id
JOIN hotel h ON h.hotel_id=t.hotel_id
WHERE tf.feture_id IN ?
AND h.hotel_city_id=?
GROUP BY tf.type_id, h.hotel_id, h.hotel_name, h.hotel_address HAVING COUNT(tf.type_id)>=?";
$result = $dbca->prepare($hotel_list);
$result->bind_param("sii", $feture,$city_ide,$cnt_type);
$feture=(string)$finish;
$city_ide = (int)$hotel_city_id;
$cnt_type=(int)$cn;
$result->execute();
$res = $result->get_result();
while ($obj = $res->fetch_object()) {
$hotels[] = $obj;
}
Because it is a design requirement that you must use the IN operator and prepared statements, you need a way to convert the PHP array of (value 1, value 2, value 3, ... value n) into an SQL array (value 1, value 2, value 3, ... value n). You'll need an intermediate step, as PHP objects cannot be directly translated into SQL without the aid of functions or loops of some sort.
Your thought process should be: what do the two variables have in common? Answer: they're both lists and they can both be represented by strings. To solve your problem, then, you want to transform the PHP list into a comma-separated string, into an SQL array, and then check in the SQL query if the specified column has a value in that array.
There are only two changes you need to make to your code to accomplish this:
1) Create a variable $feature_ids_str and make it the comma-separated string version of whatever array holds your feature IDs (as per the comments on your question, it really would be helpful if you gave us some more code to explain where some of these variables were coming from). An example of the value of $feature_ids_str would be "1,5,3,7,82,4".
2) Amend your query as follows: ... WHERE tf.feture_id IN STRING_SPLIT(?, ',') ... [feture_id sic] and of course update the $result->bind_param() function accordingly.
Also, I think you're misspelling "feature".
Related
I have a search bar that passes data to the server. I am taking the sentence sent and breaking it into individual words.
I am then comparing a column against each word in the sentence.
$term = filter_var($input['term'], FILTER_SANITIZE_STRING);
$terms = explode(" ", $term);
$size = sizeof($terms);
$posts = DB::select('SELECT * FROM cars
WHERE color = ?',
$terms[0] || $terms[1] || $terms[2] || $terms[3] || $terms[4] );
What is the proper way to bind with multiple parameters on one bind?
This way would get messy, as I would want to search additional columns.
for ($i=0; $i < $size ; $i++) {
$posts = DB::select('SELECT * FROM cars
WHERE color = ? AND
WHERE model =?',
$terms[$i], $terms[$i],);
}
What is the proper way to bind with multiple parameters on one bind.
Think of this rule: You can use a parameter in an SQL query in place of one single scalar value.
That is, where you would normally use in your SQL statement one numeric constant, one quoted string constant, or one quoted date constant, you can replace that one query element with one parameter.
Parameters can not be used in place of:
Lists of multiple values
SQL expressions
SQL keywords
Identifiers like table names, column names, or database names
If you want to compare your color column to multiple values, you need multiple parameter placeholders.
$posts = DB::select('SELECT * FROM cars
WHERE color IN (?, ?, ?, ?)');
It doesn't work to pass a string containing a comma-separated list of values to a single placeholder. You end up with a query that works as if you had written it this way:
SELECT * FROM cars WHERE color IN ('12,34,56,78');
This query will run without error, but it won't give you want you want. In a numeric context, the string '12,34,56,78' has a numeric value of 12. It ignores all the rest of the characters in the string after the first non-numeric character ,. So it will succeed in searching for color 12, but it will fail to find the other colors.
PDO makes it easy to deal with lists of values, because when it is time to supply the values for a parameterized query, you can simply pass an array to the PDOStatement::execute() function.
If you don't know how many color values you need to search for, you can use PHP builtin functions to make a list of question mark placeholders that is the same length as your array of color values:
$list_of_question_marks = implode(',', array_fill(1, count($color_values), '?'));
$sql = "SELECT * FROM cars WHERE color IN ($list_of_question_marks)"
$stmt = $pdo->prepare($sql);
$stmt->execute($color_values);
You should use In to search between various items, and if it's a search, a OR operator would work better:
$posts = DB::select('SELECT * FROM cars
WHERE color in (?) or
model in (?)',
implode(',', $terms), implode(',', $terms));
I'm running a PDO query, something like:
$inputArr = array(val1, val2, val3, ...);
$qMarks = str_repeat('?,', count($inputArr) - 1) . '?';
$stmt = $db->prepare("SELECT id, name, type, level
FROM table
WHERE name IN ($qMarks)");
$stmt->execute($inputArr);
... parse the rows that have been returned
And this works exactly as expected, no hang-ups or anything.
My problem is that I need to know which value from $inputArr was used to get each row returned.
I've tried
WHERE name IN ($qMarks) AS inputVal
and
WHERE name IN ($qMarks AS inputVal)
but those crash the query.
How can I determine which input array value was used to return each row in the output?
EDIT 1
Yes, I understand that the input search value would be name, for this particular case, but the query above is only for demonstration purposes of how I am putting the search values into the query.
The actual is much more complex, and returns any name value with is close (but not always identical).
The AS keyword is not going to work as you expect it. It's mainly used for aliasing subqueries. You can't (to my knowledge) use it in a WHERE clause.
The scenario you've outlined should have the 'name' in $row['name']. If it was a different variable that you wanted to see, you'd simply add it in your SELECT clause.
Great question, and simple answer:
The WHERE name IN $qMarks)"); part of your code is only obtaining the values in your database that are matching your array, so what you can do is see which values of name are present in the row you fetched. For example:
$rows_fetched = $stmt->fetchAll(PDO::FETCHASSOC);
$inputArray = array();
foreach($rows_fetched as $value)
{
$inputArray[] = $value['name'];
}
print_r($inputArray);//printing the results
Now you have the array $inputArray with all the values used to return each row in the output. Let me know if that worked for you!
I have a problem with a question mark parameter in a prepared statement using PDO. My Query class looks like this (for now, I'm still adding functionality like data limits, custom parameters filtering and automatic detection of supported statements for the driver being used):
// SQL query
class Query {
public $attributes;
// constructor for this object
public function __construct() {
if ($arguments = func_get_args()) {
$tmp = explode(" ", current($arguments));
if (in_array(mb_strtoupper(current($tmp)), ["ALTER", "DELETE", "DROP", "INSERT", "SELECT", "TRUNCATE", "UPDATE"], true)) {
// classify the query type
$this->attributes["type"] = mb_strtoupper(current($tmp));
// get the query string
$this->attributes["query"] = current($arguments);
// get the query parameters
if (sizeof($arguments) > 1) {
$this->attributes["parameters"] = array_map(function ($input) { return (is_array($input) ? implode(",", $input) : $input); }, array_slice($arguments, 1, sizeof($arguments)));
}
return $this;
}
}
}
}
This is the code fragment which executes the query:
$parameters = (!empty($this->attributes["queries"][$query]->attributes["parameters"]) ? $this->attributes["queries"][$query]->attributes["parameters"] : null);
if ($query = $this->attributes["link"]->prepare($this->attributes["queries"][$query]->attributes["query"], [\PDO::ATTR_CURSOR => \PDO::CURSOR_FWDONLY])) {
if ($query->execute((!empty($parameters) ? $parameters : null))) {
return $query->fetchAll(\PDO::FETCH_ASSOC);
}
}
And this is how I call it in my test code:
$c1->addQuery("lists/product-range", "SELECT * FROM `oc_product` WHERE `product_id` IN (?);", [28, 29, 30, 46, 47]);
if ($products = $c1->execute("test2")) {
foreach ($products as $product) {
print_r($product);
}
}
The problem I have is I just see the first product (it's a test against a vanilla OpenCart installation) with id 28. As you can see in my code, if the passed parameter is an array, it gets automatically detected by the lambda I have in place in the Query class constructor, so it gets rendered as a string like 28,29,30,46,47.
Is there a missing parameter in PDO setup I'm missing? Or maybe there's some bug or platform limit in what I'm doing? I know there's some limitations on what PDO can do in regards to arrays, and that's why I pre-implode all arrays for them to be passed like a simple string.
There's some procedures I've seen here in SO which, basically, composes the query string like WHERE product_id IN ({$marks}), where $marks is being dynamically generated using a procedure like str_repeat("?", sizeof($parameters)) but that's not what I'm looking for (I could resort to that in case there's no known alternative, but it doesn't look like a very elegant solution).
My development environment is composed of: Windows 7 x64, PHP 5.4.13 (x86, thread-safe), Apache 2.4.4 (x86) and MySQL 5.6.10 x64.
Any hint would be greatly appreciated :)
A ? placeholder can only substitute for a single literal. If you want an IN clause to accept an arbitrary number of values, you must prepare a new query for each possible length of your array.
E.g., if you want to select ids in array [1, 2], you need a query that looks like SELECT * FROM tbl WHERE id IN (?,?). If you then pass in a three-item array, you need to prepare a query like SELECT * FROM tbl WHERE id IN (?,?,?), and so on.
In other words, you cannot know with certainty what query you want to build/create until the moment you have the data you want to bind to the prepared statement.
This is not a PDO limitation, it is fundamental to how prepared queries work in SQL databases. Think about it--what datatype would the ? be in SQL-land if you said IN ? but had ? stand in for something non-scalar?
Some databases have array-types (such as PostgreSQL). Maybe they can interpret IN <array-type> the same way as IN (?,?,...) and this would work. But PDO has no way of sending or receiving array-type data (there is no PDO::PARAM_ARRAY), and since this is an uncommon and esoteric feature it's unlikely PDO ever will.
Note there is an extra layer of brokenness here. A normal database, when faced with the condition int_id = '1,2,3,4' would not match anything since '1,2,3,4' cannot be coerced to an integer. MySQL, however, will convert this to the integer 1! This is why your query:
$pstmt = $db->prepare('SELECT * FROM `oc_product` WHERE `product_id` IN (?)');
$pstmt->execute(array('28,29,30,46,47'));
Will match product_id = 28. Behold the insanity:
mysql> SELECT CAST('28,29,30,46,47' AS SIGNED INTEGER);
+------------------------------------------+
| CAST('28,29,30,46,47' AS SIGNED INTEGER) |
+------------------------------------------+
| 28 |
+------------------------------------------+
1 rows in set (0.02 sec)
Lambda detects an array and creates coma delimited string from it, and passed argument is treated as string, so the query looks like:
SELECT * FROM tbl WHERE id IN('1,2,3,4')
'1,2,3,4' is one string value for SQL.
If you are expecting only numerical values, you can omit adding them as parameters and simply put them in the query:
$a = [28, 29, 30, 46, 47];
$s = "SELECT * FROM tbl WHERE id IN(".implode(',', array_map('intval', $a)).")";
For different data types, you have to add as many parameter placeholders as you need, and bind every parameter separately.
Following is my code showing some error in mysql query:
<?php
$con=mysql_connect('localhost','root','');
$str=$_GET["message"];
$stor=explode(" ",$str);// converting message into array
mysql_select_db('words',$con);
for($j=0;$j<=30; $j++)
{
mysql_query($con,"UPDATE blacklist SET $stor=1 where $stor=0");//if column name=element in array then make it as 1 in database
}
mysql_close($con);
?>
Your code is vulnerable to SQL Injection. Read up on prepared statements and use PDO/MySQLi.
$stor is an array object and cant be used directly in the query. If you want to use it, try using
IN('.implode(",", $stor).')
the code above does the following:
implode() - takes an array and turns it into a comma separated string.
IN() - compares the given comma separated values and returns true if at least one of them exists.
Example (implode):
implode(",", array(1,2,3)) IS EQUAL TO "1,2,3"
Example (IN):
TestID IN (1,2,3) IS SAME AS (TestID = 1 OR TestID = 2 OR TestID = 3)
You're probably getting a mysql error because your query ends up looking like this
UPDATE blacklist SET Array=1 where Array=0;
If you're just echoing out a full array, you get Array instead, you'll need to specify an array element ($stor[1] for example).
What you'll want to do is replace your for loop with a foreach so that you can just throw out the elements one at a time.
Also, your arguments are backwards.
foreach($stor as $word)
{
mysql_query("UPDATE blacklist SET $word=1 where $word=0", $con);
}
I am looking to use the contents of an array
$arr =array(24,28,30,34, 40);
and pass these into the where clause of a MySQL select statement, all my research has shown this done by using IN to pass in all the array values in one go.
I need to pass in each array element one at a time and then echo out the results of the SQL statement one at a time as the select statement is updated with the next array element.
New to programming and PHP so just need a little example to get me started...
Thanks to Zad highlighted the real issue
I need to pass each array value individually to a SQL statement as these need to be utilised in Where clause with BETWEEN, eg. WHERE age BETWEEN $array1 AND $array2 in order to determine count over an age range
thanks for all the input
You can use the implode function to build the string that contains the list;
$arr =array(24,28,30,34, 40);
$query = 'SELECT * FROM mytable WHERE id IN (' .implode($arr, ', '). ' )';
echo $query;`
http://codepad.org/tLPZxq8P
http://mx2.php.net/manual/en/function.implode.php
try it with escaping the argument
foreach($arr as $array_element) {
$query = 'SELECT * FROM table WHERE field = \''.mysql_real_escape_string($array_element).'\'';
//your statement
}
You can use a foreach function:
// make connection to mysql server
foreach ( $arr as $element ) {
$statement = "SELECT whatever FROM wherever WHERE something = $element"; // maybe a little validation here wouldn't hurt either
// execute statement
// process results
} // end of foreach
// close connection
$arr =array(24,28,30,34, 40);
$a = 'SELECT * FROM foo WHERE bar IN('.implode(',',$arr).')';
Edit: I'll admit, I didn't fully read the question, the title is misleading - consider changing that.
I need to pass in each array element one at a time and then echo out
the results of the SQL statement one at a time as the select statement
is updated with the next array element.
Could you explain how the scenario a bit better?