Building an SQL query using multiple (optional) search fields - php

I have a form that is going to be used to search through a table of support tickets.
the user can search from a few difficult optional fields.
Date (to/from)
Ticket Status
Engineer
Ticket Contact
I'm wondering what is the best way to deal with optional search filters. So I have a query that takes in parameters from the user. So if the user searches using both the from and to dates then the query would want to include BETWEEN. So do I have to write a different query for if the user searches for only from. or another query when the user has not added any date parameters? Then what if the status dropdown is blank? Is that another query?
Any help to clear this up would be great!
Jonesy

Build your query in parts. Start with whatever is constant in your query, and add on more SQL depending on what extra conditions:
$query = "SELECT ...
FROM ...
WHERE [where conditions that are always going to be present]";
if (isset($_POST['date_from']) && isset($_POST['date_to']))
{
$query .= ... // query code for dealing with dates
}
if (isset($_POST['status']))
{
$query .= ... // deal with status
}
// etc.
// Once you have your query fully built, execute it
$result_set = mysql_query($query);
This code is obviously just a skeleton, but that's how I would construct my query.

Hard to say without knowing what sort of DB abstraction you're using, but assuming you're hand-writing the SQL, it's fairly simple, just build up sections of your where clause individually for each variable. (Assuming here that your vars are already escaped/quoted.)
$where_clause = array();
if (!empty($date_from)) {
$where_clause[] = "table.date >= $date_from";
}
if (!empty($date_to)) {
$where_clause[] = "table.date <= $date_to";
}
if (!empty($status)) {
$where_clause[] = "status = $status";
}
$query = 'select * from table where ' . join(' and ', $where_clause);

This is an elegant way that I use alot and wish will help you too:
$q = 'SELECT * FROM Users';
$buildQ = array();
if (empty($idOrName) === false) {
$buildQ[] = '(userid = "' . $idOrName . '" OR username LIKE "%' . $idOrName. '%")';
}
if (empty($nickname) === false) {
$buildQ[] = 'nickname="' . $nickname . '"';
}
if (empty($salary) === false) {
$buildQ[] = 'salary="' . $salary . '"';
}
// ... any other criterias like above if statements
if (count($buildQ) === 1) {
$q .= ' WHERE ' . $buildQ[0];
} else if (count($buildQ) > 1) {
$count = 0;
foreach ($buildQ as $query) {
if ($count === 0) {
$q .= ' WHERE ' . $query;
} else {
$q .= ' AND ' . $query;
}
$count++;
}
}

I think it would be better if You generate query dynamically at runtime based on which fields are filled. So You could make some helper which appends specific query fragments if only one date is passed and the other one is null, or when both are passed and so on.

Related

Dynamic "Where" clause in wpdb->prepare query

In the form, none of the inputs are mandatory. So, I want to have a dynamic "where" clause inside the wpdb query.
Presently this is the query:
$data = $wpdb->get_results($wpdb->prepare("SELECT * FROM
`wp_gj73yj2g8h_hills_school_data` where
`school_zipcode` = %d AND `school_type` = %s AND `school_rating` = %s
;",$selectedZip,$selectedType,$selectedRating));
if a user enters only school_zipcode then the where clause should have only "school_zipcode" column.
Same way for other combinations.
I would not make things complicated with dynamic where clauses... I would write PHP code which creates the query. For example...
NOTE!! THIS CODE IS NOT TESTED ON SERVER, IT'S JUST AN IDEA HOW TO SOLVE THE PROBLEM!
<?php
$where_query = array();
// Make sure to escape $_POST
if (!empty($_POST['school_zipcode')) {
$where_query[] = "school_zipcode='" . $_POST['school_zipcode'] . "'";
}
// Make sure to escape $_POST
if (!empty($_POST['school_type')) {
$where_query[] = "school_type='" . $_POST['school_type'] . "'";
}
// Should result in WHERE school_zipcode='123' AND school_type='text'
$where_query_text = " WHERE " . implode(' AND ', $where_query);
$data = $wpdb->get_results($wpdb->prepare("SELECT * FROM `wp_gj73yj2g8h_hills_school_data` " . $where_query_text . ";"));

Dynamic select query in mysql?

I am using mysql as my database and php as server side language.
As we know that we can select data from database using select query.
Below example is important!!
select * from table
select name from table
select name,salary from table where salary > 10000
etc..........
now, for different select query of a table we need different select method. because every time select * is not good because it takes a huge time.
Now, My Question is how write dynamic single get method of a single table by which we can achieve our requirement (shown in example...)?
I will pass the array of parameters in the argument of the function.. for ex. in php
public get($arr)
{
//code goes here
}
I want to fetch the $arr and want to change the sql dynamically..
Don't want any join query just simple select as shown in above..
Depending on how you want to do it, you can do something like this:
public get($arrfield, $arrtable, $arrwhere)
{
$str = "SELECT " . $arrfield . " FROM " . $arrtable . " WHERE " . $arrwhere;
return $str;
// You can return the query string or run the query and return the results
}
Trust me, to write all three queries is not that too hard a job that have to be avoided at any cost.
Please, do not obfuscate a precious SQL language into unreadable gibberish. Not to mention innumerable security breaches of your approach.
What you should think of is a function that lets you to use parameters. Thus, better make our function like this
function mysqli($mysqli, $query, $params, $types = NULL)
{
$statement = $mysqli->prepare($select);
$types = $types ?: str_repeat('s', count($params));
$statement->bind_param($types, ...$params);
$statement->execute();
return $statement;
}
and run your every query as is, only providing placeholders instead of variables
select * from table:
you'll never need a query like this
select name from table
$names = mysqli($db, "select name from table")->get_result->fetch_all();
`select name,salary from table:
$stmt = mysqli($db, "select name from table where salary > ?", [10000]);
$names = $stmt->get_result->fetch_all();
See - the query itself is the least code portion. Your concern should be not SQL but useless reprtitive parts of PHP code used to run a query and to fetch the data.
Here is the structure of the dynamic query.Please add required validation.You can add 'Or' clause also.On the basis of parameter or data type you can do it. Like
public SelectTable($arrfield, $table, $arrwhere, $arrgroup)
{
if(!empty($arrfield))
{
$fields = implode('`,`',$arrfield);
}
else
{
$fields = '*';
}
if(!empty($arrwhere))
{
foreach($arrwhere as $fieldName=>$fieldValue)
{
if(is_array($fieldValue))
{
$cond .= "`fieldName` in (". implode(',',$fieldValue) );
}
else
$cond .= "`fieldName` = '" . addslashes($fieldValue)."'";
}
}
else
{
$cond = '1';
}
if(!empty($arrgroup))
{
$groupBy .= " group by ";
foreach($arrgroup as $field=>$value)
{
$groupBy .= $field . " " . $vale;
}
}
}
$str = "SELECT " . $fields . " FROM " . $table . " WHERE " . $cond . $groupBy;
return $str;
// You can return the query string or run the query and return the results
}

Handling optional search parameters in a PHP SQL query

I'm querying my SQL database in a PHP file from up to three optional search fields (passed through by jQuery). Any one, two or three of these fields can be used at any time to make the query as expansive or as narrow as the user likes. If nothing is in a search field nothing will be returned.
I've written the code so far to handle very basic one search queries and have just begun to add in the multiple parameters - this is where it's starting to get tricky. I can query two fields together without too much bother but adding a third LOCATION parameter is beginning to take up too much code for all of the querying possibilities a user might make.
Here's how my PHP file is set up for two parameters:
if (!empty($_POST['title']) && (!empty($_POST['name'])))
{
require '../db/connect.php';
$sql = "SELECT
....
FROM
....
WHERE
`table 3`.`TRACKTITLE` = '" . mysql_real_escape_string(trim($_POST['title'])) . "' AND `table 3`.`ARTIST` = '" . mysql_real_escape_string(trim($_POST['name'])) . "'";
}
if (!empty($_POST['name']))
{
require '../db/connect.php';
$sql = "SELECT
...
FROM
...
WHERE
`table 3`.`ARTIST` = '" . mysql_real_escape_string(trim($_POST['name'])) . "'";
}
if (!empty($_POST['title'])) {
require '../db/connect.php';
$sql = "SELECT
...
FROM
...
WHERE
`table 3`.`TRACKTITLE` = '" . mysql_real_escape_string(trim($_POST['title'])) . "'";
}
$result = mysql_query($sql);
$data = array();
while ($array = mysql_fetch_assoc($result)) {
$data[] = $array;
Which is the simplest way to build a query with multiple optional parameters in PHP, accounting for any additional parameters that might be added on at a later date? I've read up on isnull values but do they perform a similar function to !emtpy?
Do something along this line:
$whereclauses = array();
$subsets = false;
// for every field
if(!empty($_POST['name']))
{
$subsets = true;
$whereclauses[] = " artist = ". mysql_real_escape_string(trim($_POST['name']));
}
if($subsets)
{
$whereclauses = implode(", ". $whereclauses);
}
else
{
$whereclauses ="";
}
// now build your query

php mysql multiple field search empty fields

<?php
if(isset($_POST['submit'])) {
$fields = array('field1', 'field2', 'field3');
$conditions = array();
foreach($fields as $field){
if(isset($_POST[$field]) && $_POST[$field] != '') {
$conditions[] = "`".$field."` like '%" . mysql_real_escape_string($_POST[$field]) . "%'";
}
}
$query = "SELECT * FROM customer ";
if(count($conditions) > 0) {
$query .= "WHERE " . implode (' AND ', $conditions);
}
$result = mysql_query($query);
$say = mysql_num_rows($result);
if ($say == 0) {
echo "<tr>no result.</tr>";
} else {
echo '...';
while($row = mysql_fetch_array($result))
{
...
}}
} ?>
Why doesn't this code checking empty fields? It returns results that has empty field even form submits empty.
The only improvement I think of is trim():
if(isset($_POST[$field]) && trim($_POST[$field]) != '') {
however, I am sure it is not the issue.
Have you ever thought of printing the resulting query out?
Look, you're writing a program to create some string (SQL query). But for some reason never interested in this program's direct result, judging it by some indirect results. May be it's data/query logic makes such results, but the query itself is okay?
if the query is still wrong - continue debugging.
Echo everything involved - print variables, condition results, intermediate results in the loop - and look for inconsistencies
$query = "SELECT * FROM customer ";
if(count($conditions) > 0) {
$query .= "WHERE " . implode (' AND ', $conditions);
}
When form is submitted empty ($conditions=0) it returns all table (select * from customer).
Added an else condition and fixed. Thanks for print query advices.
For checking something is empty or not. You can use empty() method.
Check this:
empty()
isset() only check whether that object/variable is set or not. For more details check this
isset()

select table filter by querystring php

ok so I've been trying for a while now to get this to work but there has to be a better solution than what im thinking about. I'm fairly new to php/mysql so not sure how to do the following:
I have a search box that contains dropdowns for country, state, city
Now if the user only selects country and clicks on search it needs to filter the select by just country and show everything else.
if(!empty($_REQUEST['city']))
$city = $_REQUEST['city'];
else
$city= "%";
if(!empty($_REQUEST['state']))
$state= $_REQUEST['state'];
else
$state= "%";
if(!empty($_REQUEST['country']))
$country= $_REQUEST['country'];
select * from table where country = $country and state = $state and city = $city
problem with this is that those columns are ints so I can't use the "%" to filter it. I hope I was able to explain it any help is more than welcome. Thanks in advance
If you don't want to constrain a column, simply omit it from your query
never insert a string from $_REQUEST directly into a query string -- classic SQL injection flaw.
you probably want to enforce some sort of limit, lest the query return every single result in your database.
example:
<?php
$conditions = array();
if(!empty($_REQUEST['city']))
$conditions[] = "city = " . mysql_real_escape_string($_REQUEST['city']);
if(!empty($_REQUEST['state']))
$conditions[] = "state = " . mysql_real_escape_string($_REQUEST['state']);
if(!empty($_REQUEST['country']))
$conditions[] = "country = " . mysql_real_escape_string($_REQUEST['country']);
$sql = 'select * from table ';
if(!empty($conditions))
$sql .= ' where '. implode(' AND ', $conditions);
$sql .= ' LIMIT 1000';
$where = array();
if(!empty($_REQUEST['city'])) $where[] = "city = '".(int)$_REQUEST['city']."'";
if(!empty($_REQUEST['state'])) $where[] = "state = '".(int)$_REQUEST['state']."'";
if(!empty($_REQUEST['country'])) $where[] = "country = '".(int)$_REQUEST['country']."'";
$wherestring = if(count($where) != 0) ? " WHERE ".implode(' AND ', $where) : "" ;
$query = "SELECT * FROM table".$wherestring;
You may want to consider writing several query strings, one for just country, one for state and country and one for city, state and country. Alternatively you can assemble the query string based upon the different parameters you have to work with.
Example:
if(isset() || isset() || isset() ) //make sure at least one is set
{
$query_string = "SELECT * FROM table WHERE ";
if(isset($_REQUEST['country']))
{
$country = $_REQUEST['country'];
$query_string .= " country = $country";
}
if(isset($_REQUEST['state']))
{
$state = $_REQUEST['state'];
$query_string .= " state = $state";
}
if(isset($_REQUEST['city']))
{
$city = $_REQUEST['city'];
$query_string .= " city = $city";
}
}
else
{
//Else, if none are set, just select all the entries if no specifications were made
$query_string = "SELECT * FROM table";
}
//Then run your query...
So in english, the first thing you do is check your parameters, making sure you have something to work with before you try and concatenate empty variables together.
Then you make the base query string (as long as we have parameters) and leave it open ended so that we can add whatever parameters you need.
Next check each parameter, and if it is set, then concatenate that parameter onto the end of the query string.
Finally process the query by sending it to the SQL server.
Good luck!
h
Here're my suggestions.
I'm giving you an answer, even though you have three already. I'm thinking mine may be easier on the code-eyes.
Do not use the raw $_REQUEST value, as it's likely that the user can poison your database by feeding it fake $_REQUEST data. Though there may be better ways to do it, keep in mind the command "mysql_real_escape_string($string)".
A common method I've seen for solving this problem is written below. (The implode idea, basically. Frank Farmer does it as well in his.)
-
$__searchWheres = array(); //Where we'll store each requirement used later
foreach( array('city','state','country') as $_searchOption) {
if ( ! empty( $_REQUEST[$_searchOption] ) ) {
$__searchWheres[] = $_searchOption . '= "' . mysql_real_escape_string( $_REQUEST[$_searchOption] ) . '"';
}
}
$__query = 'select * from table' . (count($__searchWheres) > 0 ? ' WHERE ' . implode(' AND ',$__searchWheres) : ''); //Implode idea also used by Frank Farmer
//Select from the table, but only add the 'WHERE' key and where data if we have it.
mysql_query($__query);

Categories