Filtering data with Select (advanced) [duplicate] - php

This question already has answers here:
Search Form with One or More (Multiple) Parameters
(2 answers)
Closed 4 years ago.
I'm on a project and I have 3 possibilities of filters. Filter by name,cities and province. Right now what i'm doing are simple IFs trying to think of all possibilities.
Example : it can be [Name][City][All] or [All][City][province] or [All][All][province] and it goes on in total of 8 to 9 possibilities. That means if have to do about 8 condition in my PHP code trying to catch everything.
So my question is : Is there a way on MySql to do a SELECT data1.. FROM tableName WHERE ... but when I don't give for example the city it search only with the name and the province.

This could be done in mysql or php - but imho the php solution looks cleaner. To do this, you just have to build the query on runtime.
$name = ...
$city = ...
$province = ...
$fields = [
'name' => $name,
'city' => $city,
'province' => $province
];
$where = [];
$values = [];
foreach ($fields as $field => $value) {
if ($value) {
$where[] = "$field = :$field";
$values[$field] = $value;
}
}
$sql = 'SELECT * FROM table';
if (count($where) > 0) {
$sql .= ' WHERE ' . join(' AND ', $where);
}
// using pdo
$query = $pdo->prepare($sql);
$query->execute($values);
// ...

There's a couple of approaches. One way to do it is to dynamically build the SQL text. If the options are discrete, we can just handle each condition separately, and include or not. As an example of the pattern:
start the SQL text:
$sql = "SELECT ...
FROM ...
WHERE 1=1 ";
conditionally append search conditions
if( we need to add a condition on city ) {
$sql .= " AND t.city LIKE :city ";
}
if( we need to add a condition on province ) {
$sql .= " AND t.province LIKE :province ";
}
if( we need to add a condition on name ) {
$sql .= " AND t.name LIKE :name ";
}
finish the SQL text
$sql .= " ORDER BY ...";
prepare the SQL text (here is a good place to echo/var_dump/log the contents of $sql for debugging)
$sth = $dbh->prepare($sql);
conditionally bind values for any of the search conditions we added
if( we need to add a condition on city ) {
$sth->bindValue(':city',$city);
}
if( we need to add a condition on province ) {
$sth->bindValue(':province',$province);
}
if( we need to add a condition on name ) {
$sth->bindValue(':name',$name);
}
execute
$sth->execute();
Another alternative is to use static SQL with expression in the WHERE clause, using a "special" reserved value to represent "no search".
In this example, we are using a zero-length string represent "no search condition" ...
$sql = "SELECT ...
FROM ... t
WHERE ( :city1 = '' OR t.city LIKE :city2 )
AND ( :province1 = '' OR t.province LIKE :province2 )
AND ( :name1 = '' OR t.name LIKE :name2 )
ORDER BY ...";
$sth = $dbh->prepare($sql);
$sth->bindValue(':city1' , $city );
$sth->bindValue(':city2' , $city );
$sth->bindValue(':province1' , $province );
$sth->bindValue(':province2' , $province );
$sth->bindValue(':name1' , $name );
$sth->bindValue(':name2' , $name );
$sth->execute();

You could do something like this, storing your filters in an array and checking for the existence of each. If the filter has a value, dynamically add it to the where clause by using an array of where statements.
$filters = ['name', 'city', 'province'];
$where = [];
foreach($filters as $filter) {
if(!empty($_POST[$filter])) {
$param_name = ":{$filter}";
$where[] = "{$filter} = {$param_name}";
$params[$param_name] = $_POST[$filter];
}
}
$where_str = !empty($where) ? 'WHERE ' . join(' AND ', $where) : '';
$sql = "SELECT * FROM table {$where_str}";
$db = new PDO(<connection_str>);
$stmt = $db->prepare($sql);
$results = $stmt->execute($params);

Related

How to create an SQL query using an array?

I have an Array with data and I want to create an SQL statement (In which I am going to use where to where in).
I have tried to make query but no success.
SQL will be like :
SELECT *
FROM documents
WHERE category = "recruitment"
AND sub_category in("forms")
OR category = "onboarding"
AND sub_category IN ("sop")
OR category = "policies"
AND sub_category IN("forms");
and Array is this :
{"Recruitment":["Forms"],"Onboarding":["Sop"],"Policies":["Forms"]}
I have tried this code :
foreach ($db_sub as $data=>$key){
$query = "where document.category = ".$data." or where document.sub_category in ('".$key."')";
}
But getting error array to string conversion. Plz help me.
Thanks in advance.
Error :
You are trying to concatenate a string with an array. Since your array's values are also arrays, you will have to convert them to string first. It could be done with the join function.
foreach ($db_sub as $data=>$key){
$query = "where document.category = ".$data." or where document.sub_category in ('".join(", ", $key)."')";
}
Now you shouldn't get array to string conversion error.
Use this example to create the required SQL query:
$whereClause = [];
$params = [];
foreach ($db_sub as $data => $key){
if (!is_array($key)) $key = [$key];
$whereClause[] = '(documents.category = ? AND documents.sub_category IN (?' . str_repeat(', ?', count($key) - 1) . '))';
$params[] = $data;
$params = array_merge($params, $key);
}
$whereClause = !empty($whereClause) ? 'WHERE ' . implode(' OR ', $whereClause) : '';
$query = "SELECT * FROM documents $whereClause";
$sth = $pdo->prepare($query);
$sth->execute($params);
$result = $sth->fetchAll();
Here variable $pdo is a PDO object

How to enter variable into prepared stmt that will retrieve all from the column?

I'm making a search filter on my events website. There are 3 drop down inputs: Location, event type, date.
When the user submits the search filter, the form posts values that changes the mysql query which will display different events on the user screen. I'm having trouble finding a flexible solution.
Right now my query is like this:
$filter = $database->prepared_query("SELECT * FROM onlineevent WHERE event_location = (?) AND event_type = (?) AND event_date = (?)", array($l, $t, $d));
How can I make $l retrieve ALL possible values for event_location? The same goes for $t and $d. I thought I could set $l to '*' but that doesn't work.
The problem now is if the user doesn't select a value for $l, and they do select a value for $t and $d, then the query doesn't work. I want to set the default value for each variable to bring all results for each condition.
So if the user doesn't select any filter and submits the form, the query I'm looking for would look something like this:
$filter = $database->prepared_query("SELECT * FROM onlineevent WHERE event_location = (?) AND event_type = (?) AND event_date = (?)", array(ALL, ALL, ALL));
The original version of Ali_k's answer was almost right, but made the mistake of including the whole clause as a parameter, rather than just the value. That would cause the whole clause to be seen as a string value, rather than as code with values within it.
The idea of building up the string gradually - and, crucially, only adding a clause if there's actually value specified in the search parameters - is correct though. You also need need to build up the parameter array separately at the same rate.
Here's a version which should actually execute correctly:
$sql = "SELECT * FROM onlineevent";
$sqlfilters = "";
$parameters = array();
if( !empty($l) ){
$sqlfilters .= " event_location = ?";
$parameters[] = $l;
}
if( !empty($t) ){
$sqlfilters .= ($sqlfilters != "" ? " AND" : "")." event_type = ?";
$parameters[] = $t;
}
if( !empty($d) ){
$sqlfilters .= ($sqlfilters != "" ? " AND" : "")." event_date = ?";
$parameters[] = $d;
}
if ($sqlfilters != "") sqlfilters = "WHERE ".$sqlfilters; //add a WHERE clause if needed
$sql .= $sqlfilters; //add the filters to the initial SQL
$filter = $database->prepared_query($sql, $parameters);
Maybe I'm misunderstanding you but aren't you just looking for:
$filter = $database->prepared_query("SELECT * FROM onlineevent")
OR
$filter = $database->prepared_query("SELECT * FROM onlineevent WHERE event_location IS NOT NULL AND event_type IS NOT NULL AND event_date IS NOT NULL")
Your question is not quite clear and it is also not clear how the prepare function works, but here is my suggestion:
$array = array();
$query_parms = '';
if( !empty($l) ){
$array[] = $l;
$query_parms .= 'event_location = (?)';
}
if( !empty($t) ){
$array[] = $t;
$query_parms .= count($array) > 1 ? 'AND event_type = (?)' : 'event_type = (?)';
}
if( !empty($d) ){
$array[] = $d;
$query_parms .= count($array) > 1 ? 'AND event_date = (?)' : 'event_date = (?)';
}
$filter = $database->prepared_query("SELECT * FROM onlineevent WHERE " . $query_parms, $array);

Variable sql query depending on number of search parameter

I need to do a sql query in php for search some entries (so using WHERE). But the field used to search could be of variable number.
I have a page with a search form, with 4 Field. It sends via POST the fields to a search.php that make a query:
$gomme_sql = $data->query("SELECT * FROM table WHERE parameter1 = '$_POST['name1']' AND parameter2 = '$_POST['name2']' ORDER BY id ASC");
But I don't know which field are filled. So, if I don't enter anything in field1 from the search form, I shouldn't have parameter1 = '$_POST['name1']' in the WHERE query.
Have you any idea how to obtain this?
Thank you
You can check the post data before appending that clause to the query in a way like this:
edit: adding additional check:
$sql="select something from someTable ";
if(!empty($_POST['name1']) || !empty($_POST['name2'])) // add as many as you like
{
$sql.=" where ";
if(!empty($_POST['name1']))
{
$sql.="parameter1= $_POST['name1']";
}
// etc etc...
}
$sql.=" ORDER BY id ASC";
and so on.
Having said that, please, please use prepared statements with this sort of input from the user. This is SUPER open to sql injection. Please do read this: How can I prevent SQL injection in PHP?
You can write generic sql select function like this , if you need more complex SQL just modify it.
<?php
function sqlSelect($table, $sel, $wh = '', $groupby = '', $order = '', $add = '') {
$tb = $table;
if (is_array($table)) {
$tb = implode(',', $table);
}
if ($wh) {
if (is_array($wh)) {
$w = array();
foreach ($wh as $k => $v) {
$v = mysqli_real_escape_string($v);
if (is_null($v))
$w [] = "$k=null ";
else
$w [] = "$k ='$v'";
}
$wh = 'where ' . implode(' and ', $w);
}else {
$wh = "where $wh";
}
}
if ($groupby)
$groupby = "group by $groupby";
if ($order)
$order = "order by $order";
$sql = "select $sel from $tb $wh $groupby $order $add ";
return $sql;
}
//set _GET as this is console test
$_GET['name1']='Bob';
$where = array(
'name1'=>$_GET['name1']
);
echo sqlSelect('sometable' , '*' , $where) ."\n";
// select * from sometable where name1 ='Bob'
//or some complex stuff
echo sqlSelect('persons', "age,status" , array('name'=>'Maria' , 'likes'=>'PHP') , null, 'age' , 'limit 20');
//select age,status from persons where name ='Maria' and likes ='PHP' order by age limit 20

Build dynamic WHERE clause in mySQL

I have this code and it works great, if I just want to search by office name. However I need to be able to search by "Office and/or First Name and/or Last Name", any combination of the three.
$firstName = $_POST["firstName"];
$lastName = $_POST["lastName"];
$officeName = $_POST ["officeName"];
$query = "SELECT
e.*,
e.id emp_id,
o.*
";
$query .= "FROM
employee_data e,
office o,
employee_office_pivot p
";
$query .= "WHERE
1=1
AND e.id=p.employee_id
AND p.office_id=o.id
AND o.office_name= '".$officeName."'
";
How can I build the WHERE clause, so that it will accept any of the three columns, or none if they are null.
Thanks,
Richard
Something like this?
$query .= "WHERE
1=1
AND e.id=p.employee_id
AND p.office_id=o.id
AND (o.office_name= '".mysqli_real_escape_string($officeName)."'
OR o.office_name= '".mysqli_real_escape_string($firstName)."'
OR o.office_name= '".mysqli_real_escape_string($lastName)."')
";
I used mysqli_real_escape_string() here as an example, you should use the correct and necessary precautions to avoid SQL injection in your system.
You can use arrays to dynamically construct your SQL:
/**
* The items you expect to receive from $_POST. I prefer defining these ahead of time - when feasible -
* so that you can reference them without worrying about throwing an error if they are not set.
*/
$options = array_fill_keys(array('firstName', 'lastName', 'officeName'), false);
$post = array_merge($options, $_POST);
/**
* Your base SQL query.
*/
$sql = 'SELECT ...columns... FROM ...tables... WHERE 1 = 1';
$where = array();
/**
* If $_POST items are present, sanitize and create SQL
*/
if ( $post['firstName'] ) {
$where[] = "employee_first_name = '".mysqli_real_escape_string($post['firstName'])."'";
}
if ( $post['lastName'] ) {
$where[] = "employee_last_name = '".mysqli_real_escape_string($post['lastName'])."'";
}
if ( $post['officeName'] ) {
$where[] = "office_name = '".mysqli_real_escape_string($post['officeName'])."'";
}
/**
* One or more $_POST items were found, so add them to the query
*/
if ( sizeof($where) > 0 ) {
$sql .= ' AND '.implode(' AND ', $where);
}
You can use the same technique to dynamically add columns, joined tables, etc. to the SQL. (Hint: build the entire SQL statement using an array.) You can also very easily modify this to use combinations of AND and OR.
$values = array(
'firstName' => 'someFirstName',
'lastName' => 'someLastName',
'officeName' => 'someOfficeName'
);
foreach( $values as $col => $val )
{
$where .= "$key = '$balue' ";
}
Though this is SQL injection vulnerable.

How to build a dynamic mysql query to suit all users

I need your help with my website search functionality. I'm developing a members area wherein users can search other registered users based on certain criteria, or combination of criteria.
My problem now is how to build a dynamic mysql query to suit the need of each combination of search criteria, where the number of criteria is variable.
Normally, I can write with a pre-determined set of criteria using
WHERE param1 = '$param1'
AND param2 = '$param2'
AND param3 = '$param3'
How do I solve this problem?
If the issue is that you don't know which of the criteria the user will pick, but want to return results for "blank" criteria, you can use the following:
$criteria_1 = $_POST['criteria_1'];
$criteria_2 = $_POST['criteria_2'];
$criteria_3 = $_POST['criteria_3'];
if(!$criteria_1 && !$criteria_2 && !$criteria_1) {
echo "You must select at least one criteria!";
} else {
// Run query mentioned below and return results.
}
THe query would then look like:
SELECT * from mytable
WHERE
(criteria1 = '$criteria_1' OR '$criteria_1' = '') AND
(criteria2 = '$criteria_2' OR '$criteria_2' = '') AND
(criteria3 = '$criteria_3' OR '$criteria_3' = '')
This will treat any blank (non-selected) parameters as blank and ignore them. Be aware that with the above, if no criteria are given, it will return all results.
Another way to write the above is:
SELECT * from mytable
WHERE
criteria1 IN ('$criteria_1', '') AND
criteria2 IN ('$criteria_2', '') AND
criteria3 IN ('$criteria_3', '')
Again, allowing for no entry at all to return all criteria1 results.
Here's a generic example of what you're asking:
$query = "SELECT * FROM mytable";
if ($_POST['name'] == "Jack") {
$query .= " WHERE name = 'Jack'";
}
if ($_POST['name'] == "Bob") {
$query .= " WHERE name = 'Bob'";
}
if ($_POST['state'] != "") {
$query .= " AND state = '" . mysql_real_escape_string($state) . "'";
}
//So now, in total, your query might look like this
//"SELECT * FROM mytable WHERE name = 'Bob' AND state = '$state'"
$result = mysql_query($query);
You just add to your $query string with if statements, then execute the query once you've checked all $_POST variables.
I've seen queries like this, so that if you don't want to put in a value for a particular column, you pass in NULL for that column:
SELECT *
FROM users
WHERE param1 = :param1
UNION
SELECT *
FROM users
WHERE param2 = :param2
UNION
SELECT *
FROM users
WHERE param3 = :param3
This assumes that you'll have each column indexed and you're performing Boolean AND searches (and using PDO).
use your scripting language (php) to loop over the inputs...
then have a structure like this:
WHERE 1=1
then add your
AND paramx = '$px'
to it...
$criteria = array();
//Populate your criteria and parameter arrays with input from the web page here
...
// $criteria should now have stuff in it
$sql = "SELECT * FROM mytable ";//Or whatever your sql query is
$count = 0;
foreach ($criteria as $key => $parameter) {
if ($count == 0) {
$sql = $sql."WHERE ".$key." = ".$parameter;
} else {
$sql = $sql."AND ".$key." = ".$parameter;
}
$count++;
}
That said, this is highly vulnerable to sql injection attack. Try using PHP PDO
An option is also to build the query from php/asp or whatever you working with, like this
$param1 = (isset($searchParam1) ? "param1 = $searchParam2" : "1");
$param2 = (isset($searchParam2) ? "param2 = $searchParam2" : "1");
$param3 = (isset($searchParam3) ? "param3 = $searchParam3" : "1");
and the query would be like
SELECT ... WHERE $param1 $param2 $param3
would like to share this code to build dynamic mysql query with PHP
Thx & regards
$vocabulary = (($page == "vocabulary") ? "image_name <> ''" : "");
$groupcat = (($group != "") ? "group = $group" : "");
$var = array($vocabulary, $groupcat);
$counter = "0";
$param = "";
for ($i=0;$i<count($var);$i++)
{
if ($counter == "0" && $var[$i] != "" ) $param = "WHERE ";
if ($counter > "0" && $var[$i] != "" ) $param = " AND ";
if ($param != "")
{
$condition .= $param . $var[$i];
$param="";
$counter++;
}
}
echo "Condition : ". $condition;

Categories