Build multiple "or" in mySQL based on user input - php

I'm trying to figure out the best possible way to build this. Here's what I have so far:
Sum up all the widgets sold in a single zip code:
select `Widgets`, SUM(`number sold`) as total_sold from mytable where
`Widgets`="Super Widget" and `zip_code`="35801"
So far, so good. I can do something similar if I want sales from two zip codes:
select `Widgets`, SUM(`number sold`) as total_sold from mytable where
`Widgets`="Super Widget" and (`zip_code`="35801" or
`zip_code`="12345")
Works great.
What I need to do is be able to set this up such that the user can select multiple zip codes without knowing in advance how many they want. Could be 2 or 20. Is there a way to structure this query as an array or similar? Pseudo-code:
select `Widgets`, SUM(`number sold`) as total_sold from mytable where
`Widgets`="Super Widget" and
(`zip_code`=in_array[35801,12345,00124,43562,12441])
This would show all the sales in these 5 zip codes. This would be a simple query to build by getting user input on the front end as a comma separated input.
Any suggestions would be appreciated.

Use in
select `Widgets`, SUM(`number sold`) as total_sold from mytable where `Widgets`="Super Widget" and `zip_code` in (35801,12345,00124,43562,12441)

You can use the IN function (here's an example from the link):
SELECT 'wefwf' IN ('wee','wefwf','weg');
Applied to your situation, it might look like:
...
and (`zip_code` IN ('35801', '12345', '00124', '43562', '12441'))

As mentioned, you can use IN function of SQL, and if you are building this query in PHP code (you added a php tag), then you can use implode function to create the "in array".
$arr = ['a', 'b', 'c'];
$line = implode(',', $arr);
echo $line; // Will output: a,b,c
Notice that writing the values directly to the query string is very dangerous, as it will expose your application to SQL injection attacks.
UPDATE:
You can use IN with PDO, with a little workaround - you can create question mark place holder in the query for each one of the values.
We will use str_repeat function to create the required question mark place holders, and rtrim function to remove the last comma.
Assuming your list of values is stored in $arr and your PDO reference is in $pdo:
$arr = ['value 1', 'value 2', 'value 3' ...];
$placeHolders = rtrim(str_repeat('?,', cound($arr)), ',');
$query = "SELECT * FROM table WHERE id IN ($placeHolders)";
$stmt = $pdo->prepare($query);
$stmt->execute($arr);
The variable $placeHolders will hold a string with '?' place holders for parameters, in the amount of the number of elements in the array, and then you can pass the array to the execute function of the prepeared statement.

Related

How to use "IN" operator in prepared statement in php

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".

PHP, MySQL - Return which value was used when input is an array?

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!

prevent sql injection on query with variable (and large) number of columns

I have a sql query that is generated using php. It returns the surrogate key of any record that has fields matching the search term as well as any record that has related records in other tables matching the search term.
I join the tables into one then use a separate function to retrieve a list of the columns contained in the tables (I want to allow additions to tables without re-writing php code to lower ongoing maintenance).
Then use this code
foreach ($col_array as $cur_col) {
foreach ($search_terms_array as $term_searching) {
$qry_string.="UPPER(";
$qry_string.=$cur_col;
$qry_string.=") like '%";
$qry_string.=strtoupper($term_searching);
$qry_string.="%' or ";
}
}
To generate the rest of the query string
select tbl_sub_model.sub_model_sk from tbl_sub_model inner join [about 10 other tables]
where [much code removed] or UPPER(tbl_model.image_id) like '%HONDA%' or
UPPER(tbl_model.image_id) like '%ACCORD%' or UPPER(tbl_badge.sub_model_sk) like '%HONDA%'
or UPPER(tbl_badge.sub_model_sk) like '%ACCORD%' or UPPER(tbl_badge.badge) like '%HONDA%'
or UPPER(tbl_badge.badge) like '%ACCORD%' group by tbl_sub_model.sub_model_sk
It does what I want it to do however it is vulnerable to sql injection. I have been replacing my mysql_* code with pdo to prevent that but how I'm going to secure this one is beyond me.
So my question is, how do I search all these tables in a secure fashion?
Here is a solution that asks the database to uppercase the search terms and also to adorn them with '%' wildcards:
$parameters = array();
$conditions = array();
foreach ($col_array as $cur_col) {
foreach ($search_terms_array as $term_searching) {
$conditions[] = "UPPER( $cur_col ) LIKE CONCAT('%', UPPER(?), '%')";
$parameters[] = $term_searching;
}
}
$STH = $DBH->prepare('SELECT fields FROM tbl WHERE ' . implode(' OR ', $conditions));
$STH->execute($parameters);
Notes:
We let MySQL call UPPER() on the user's search term, rather than having PHP call strtoupper()
That should limit possible hilarious/confounding mismatched character set issues. All your normalization happens in one place, and as close as possible to the moment of use.
CONCAT() is MySQL-specific
However, as you tagged the question [mysql], that's probably not an issue.
This query, like your original query, will defy indexing.
Try something like this using an array to hold parameters. Notice % is added before and after term as LIKE %?% does not work in query string.PHP Manual
//Create array to hold $term_searching
$data = array();
foreach ($col_array as $cur_col) {
foreach ($search_terms_array as $term_searching) {
$item = "%".strtoupper($term_searching)."%";//LIKE %?% does not work
array_push($data,$item)
$qry_string.="UPPER(";
$qry_string.=$cur_col;
$qry_string.=") LIKE ? OR";
}
}
$qry_string = substr($qry_string, 0, -3);//Added to remove last OR
$STH = $DBH->prepare("SELECT fields FROM table WHERE ". $qry_string);//prepare added
$STH->execute($data);
EDIT
$qry_string = substr($qry_string, 0, -3) added to remove last occurrence of OR and prepare added to $STH = $DBH->prepare("SElECT fields FROM table WHERE". $qry_string)

How to use PHP Array in MySQL Select statement with BETWEEN?

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?

mysql IN parameter

When the user check more than one (checkbox) option which are then combine into a string of "apple,orange,pear"
SELECT id, pos, FROM $db WHERE dtime>='$now' AND jsub IN ('$arr[1]') ;
When I pass the string to $arr[1], it won't work correctly, how do I split into array and get mysql IN function to process correctly?
use:
$str = "SELECT id, pos, FROM $db
WHERE dtime>='$now' AND jsub IN ('".explode(',',$arr."')";
and don't forget to sanitize the parameters before ...
Use FIND_IN_SET.
SELECT id, pos, FROM $db WHERE dtime>='$now' AND FIND_IN_SET(jsub, '$arr[1]')
the question is WAY unclear, but I suspect you want something like
foreach ($arr as $key => $item) $arr[$key] = mysql_real_escape_string($item);
$in = "'".implode("','",$arr);
$sql = "SELECT id, pos, FROM $db WHERE dtime>='$now' AND jsub IN ($in)";
But man, I hate guessing.
Why don't you get yourself a static query, without any PHP code?
To see, if it ever works?
If not - ask on SO for the proper query. SQL query, not PHP code.
If yes - write a PHP code that produces the exact query.
Compare to the example one.
If failed - ask on SO for the PHP code, providing an example of the resulting query and an array.
Is it too hard rules to follow?

Categories