Build dynamic WHERE clause in mySQL - php

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.

Related

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);

Filtering data with Select (advanced) [duplicate]

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);

Constructing mysql select from $_POST array

This is the $_POST array from my form.
Array ( [prescribedid] => Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 9 [4] => 13 )
I want to create a select for any of items in the Array. I have written this, which produces the proper SELECT, but the if() to eliminate a trailing OR makes it clunky.
$query = "SELECT * ";
$query .= "FROM prescribed WHERE ";
for($i=0; $i<count($_POST["prescribedid"]); $i++) {
$query .= "prescribedid={$_POST['prescribedid'][$i]} ";
if($i < (count($_POST["prescribedid"])-1)) {
$query .= "OR ";
}
}
It produces this:
SELECT * FROM prescribed WHERE prescribedid=1 OR prescribedid=2 OR prescribedid=3 OR prescribedid=9 OR prescribedid=13
Is there another way to group the SELECTS or write the FOR() to make it cleaner, i.e. without the last IF().
$values=implode(",",$_POST["prescribedid"]);
$query = "SELECT * FROM prescribed WHERE prescribedid IN ($values)";
Sanitization is on you :)
Hi You can Use In condition. use imploade function to find comma seoarated values
$data = array('prescribedid'=>array(1,2,3,9,14));
$query = 'SELECT * FROM prescribed WHERE prescribedid IN (';
$query .= implode(',',$data['prescribedid']).')';
echo $query ;
Output
SELECT * FROM prescribed WHERE prescribedid IN (1,2,3,9,14)
Use MySQL IN clause
$ids = implode(",",$_POST["prescribedid"]);
$query = "SELECT * FROM prescribed WHERE prescribedid IN ($ids)";
You can simply use IN clause here.
Refer to MySQL IN clause
$query = "SELECT * FROM prescribed WHERE prescribedid IN ".implode(',', $_POST["prescribedid"]);

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

How can execute a MySQL query with multiple WHERE-clauses?

how would you do a mysql query where a user can choose from multiple options. Fox example I have a form that user can use to search for houses. Now I have a select box where you can chosse whether you want a house, a flat or whatever. Then I have a second box where you can choose for example the city you want the house or flat to be in. And maybe another one with the maximum price.
Now how would you do the mysql query? My problem is, I would do it like that:
if($_POST["house_type"] != 0) {
$select = mysql_query("SELECT * FROM whatever WHERE type = '".$_POST["house_type"]."'");
}
But now I only have the case that someone has chosen a house type but not any other option. So do I have to do an "if" for every possible combination of selected elements?
To emphasize my problem:
if(!isset($_POST["house_type"])) {
if($_POST["something"] == 0) {
$search_select = #mysql_query("SELECT * FROM housedata WHERE something = $_POST["whatever"]);
}
elseif($_POST["something"] != 0) {
$search_select = #mysql_query("SELECT * FROM housedata something = $_POST["whatever"] AND somethingelse = 'whatever');
}
}
elseif(!isset($_POST["house_type"])) {
if($_POST["something"] == 0) {
$search_select = #mysql_query("SELECT * FROM housedata WHERE something = $_POST["whatever"]);
}
elseif($_POST["something"] != 0) {
$search_select = #mysql_query("SELECT * FROM housedata something = $_POST["whatever"] AND somethingelse = 'whatever');
}
}
Now imagine I had like 10 or 20 different select boxes, input fields and checkboxes and I would have to do a mysql query depending on what of these boxes and fiels and checkboxes is filled. This would be a code that is extremely complicated, slow and horrible. So is there a possibility to make a mysql query like:
SELECT * FROM whatever WHERE house_data = '".$whatever."' AND (if(isset($_POST["something"])) { whatever = '".$whatever2."' } AND ...;
You get what I mean? Its a bit complicated to explain but actually its a very important question and probably easy to answer.
Thank you for your help!
phpheini
Generate the WHERE clause prior to running the SQL.
A short example:
$whereClause = "";
if ($_POST['opt1']) {
$opt1 = mysql_real_escape_string($_POST['opt1']);
$whereClause .= "AND opt1='$opt1'";
}
if ($_POST['opt2']) {
$opt2 = mysql_real_escape_string($_POST['opt2']);
$whereClause .= "AND opt2='$opt2'";
}
mysql_query("SELECT * FROM table WHERE 1 ".$whereClause);
To point you a little bit into the right direction, try something like this:
if(isset($_POST["something"]))
{
$where = " AND whatever = '".$whatever2."'";
}
else $where = '';
mysql_query("SELECT * FROM whatever WHERE house_data = '".$whatever."'".$where);
$where = array();
if($_POST["something"]) {
$where[] = " something =".$_POST["something"];
}
if($_POST["something2"]) {
$where[] = " something2=".$_POST["something2"];
}
.
.
.
//build where string
$where_ = !(empty($where) ? " WHERE ".implode(" AND ",$where) : "";
//build sql
$sql = "SELECT * ... ".$where;
write some simple query builder
$where = array();
if($_POST["something"]) {
$where[] = sprintf(" something='%s'",$_POST["something"]);
//sprintf - prevent SQL injection
}
if($_POST["something2"]) {
$where[] = sprintf(" something2='%s'",$_POST["something2"]);
}
//build where string
$where_str = " WHERE ".implode(" AND ",$where);
//build sql
$sql = "SELECT * ... $where_str";
You need to build your search string separately but the format is simply
SELECT * FROM your_table WHERE number = {$number} AND sentence = '{$sentence}';
Since you are creating the search term based on PHP logic do this:
$search = "SELECT * FROM your_table WHERE ";
if(isset($whatever)) $search .= "something = '{$whatever}'";
if(isset($whateverelse)) $search .= " AND somethingelse = '{$whateverelse}'";
$search_select = mysql_query($search);

Categories