SQL Construction & PHP - php

I'm sure this is an easy question.
If you want to produce SQL with php for a search query. So you have say 5 criteria which are all optional and may or may not be inputted by the user. You cannot guarantee any of them.
When it comes to making the SQL in php you can use :
So if they exist then you can use AND for the 4 last criteria.
But for the first criteria if you have that as a WHERE if that one is not selected then the SQL just is a list of ANDs with no starting WHERE.
Is there an easy answer?
Code I've Written :
$sql = "
SELECT *
FROM Request, Rooms
WHERE Day = ".$Day." ";
if($ModCode != ''){
$sql .="AND ModCode = ".$ModCode." ";
}
if($StartTime != ''){
$sql .="AND StartTime = ".$StartTime." ";
}
if($Length != ''){
$sql .="AND Length = ".$Length." ";
}
if($Room != ''){
$sql .="AND Request.RoomID = Rooms.RoomID ";
$sql .='AND Rooms.RoomName = "'.$Room.'" ';
}
if($Room == '' && $Park != ''){
$sql .="AND Request.RoomID = Rooms.RoomID ";
$sql .='AND Rooms.Park = "'.$Park.'" ';
}
And now I want the bit WHERE Day = $Day to be optional like the others.
Cheers

You could store all criterias in an array and then implode AND between them:
if(!empty($array)) {
$where_part = "WHERE " . implode(" AND ", $array);
}
Update:
$cond = array();
if($ModCode != ''){
$cond[] = "ModCode = ".$ModCode;
}
if($StartTime != ''){
$cond[] = "StartTime = ".$StartTime;
}
if($Length != ''){
$cond[] = "Length = ".$Length;
}
if($Room != ''){
$cond[] = "Request.RoomID = Rooms.RoomID";
$cond[] = 'Rooms.RoomName = "'.$Room.'"';
}
if($Room == '' && $Park != ''){
$cond[] = "Request.RoomID = Rooms.RoomID";
$cond[] = 'Rooms.Park = "'.$Park.'"';
}
if(!empty($cond)) {
sql .= "WHERE " . implode(" AND ", $cond);
}

I dont think this would work.
For this kind of JOIN you always need a WHERE statement with a join condition.
And after adding it, the question will make sense no more.
However, if you need conditional JOIN as well as conditional WHERE, you had to state it in the question.
Anyway, the method is quite similar.

Store your wheres in an array and only impode the array into the query if its not empty.
Something like this;
$where = array();
//build up your where's in an array
$where[] = "searchField1='blah'";
$where[] = "searchField2='foo'";
//make your query and on the where only implode the array if its not empty else return null
$sqlQuery = "
Select
*
FROM
yourTable
".(empty($where)==false ? " WHERE ".implode(" AND ", $where) : null)."
ORDER BY x
";

where 1 = 1
and (name = ? or ? is null)
and (age = ? or ? is null)
question marks are just value placeholders. you get the point.
use prepared statements and bound parameters.
anyway, each of the parenthesized predicate conditions will evaluate to true of the placeholder value is null. make sure you differentiate between the sql keyword null, and "empty" or "falsy" values like 0 or empty string. The above requires type null.

I think I understand what you mean. You could split the query like so.
$sql = "SELECT * FROM `table` WHERE ";
$sql .= ($val1 == 1) ? "`field` = 'value' " : "1 = 1 ";
$sql .= ($val2 == 2) ? "AND `field` = 'value'" : "AND 1 = 1";
Edit: A quick fix would be to add a clause that would always be true.

In MySQL you have MATCH ... AGAINST
Like so:
SELECT id, header, message FROM table WHERE MATCH(header,message) AGAINST ('".mysql_real_escape_string($search)."' IN BOOLEAN MODE)
You can combine MATCH .. AGAINST with any other WHERE-clause, like:
WHERE id > 1000 AND MATCH (...) AGAINST ('searchstring' IN BOOLEAN MODE) AND date < NOW()
This does, however, require FULLTEXT searches to be possible, so it isn't very useful on TEXT-columns in InnoDB-tables for as far as I know. But it is the perfect solution to do searches in MyISAM tables, and you can use it on VARCHAR()-columns.

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

Problems with using PDO to perform an advanced search query

I have the following code and all of the search functions work except for the title field. So I can search by genre, date, location etc... but not by title. When attempting to search by title nothing is returned at all. Can anyone help me with this?
Also, is there a more efficient way to count all the fields before limiting it for use in pagination later on?
$today = date("Y-m-d");
$query = "SELECT * FROM TABLE_NAME WHERE Date >= '$today'";
$bind = Array();
if ($_GET["Title"] && $_GET["Title"] != "") {
$query .= " and Title like %?%";
$bind['Title'] = $_GET['Title'];
}
if ($_GET["Genre"] && $_GET["Genre"] != "") {
$query .= " and Genre like %?%";
$bind['Genre'] = $_GET['Genre'];
}
if ($_GET["Location"] && $_GET["Location"] != "") {
$query .= " and Location like %?%";
$bind['Location'] = $_GET['Location'];
}
if ($_GET["Date"] && $_GET["Date"] != "") {
$query .= " and Date = %?%";
$bind['Date'] = $_GET['Date'];
}
$stmt = $db->prepare($query);
$stmt->execute($bind);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
$num = count($rows);
$query .= " ORDER BY Date LIMIT $limit, 9";
$stmt = $db->prepare($query);
$stmt->execute($bind);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
Edit: After everyone's help I thought I would post my now revised code for future reference. It turns out the other fields were not working, but instead due to the if statement all this was nested in the code simply wasn't being executed.
$today = date("Y-m-d");
$query = "SELECT * FROM TABLE_NAME WHERE Date >= '$today'";
$countq = "SELECT count(*) FROM TABLE_NAME WHERE Date >= '$today'";
$bind = Array();
if ($_GET["Title"] && $_GET["Title"] != "") {
$query .= " and Title like :title";
$countq .= " and Title like :title";
$bind[':title'] = "%{$_GET['Title']}%";
}
if ($_GET["Genre"] && $_GET["Genre"] != "") {
$query .= " and Genre like :genre";
$countq .= " and Genre like :genre";
$bind[':genre'] = "%{$_GET['Genre']}%";
}
if ($_GET["Location"] && $_GET["Location"] != "") {
$query .= " and Location like :loc";
$countq .= " and Location like :loc";
$bind[':loc'] = "%{$_GET['Location']}%";
}
if ($_GET["Date"] && $_GET["Date"] != "") {
$query .= " and Date = :date";
$countq .= " and Date = :date";
$bind[':date'] = "{$_GET['Date']}";
}
$stmt = $db->prepare($countq);
$stmt->execute($bind);
$rows = $stmt->fetchAll();
$num = count($rows);
$query .= " ORDER BY Date LIMIT $limit, 9";
$stmt = $db->prepare($query);
$stmt->execute($bind);
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
all of the search functions work
With the given query it is not true
From PDO tag wiki:
placeholders cannot represent an arbitrary part of the query, but a complete data literal only. Neither part of literal, nor whatever complex expression or a syntax keyword can be substituted with prepared statement.
Prepare FULL literal first: $name = "%$name%"; and then bind it.
As for the "more" efficient method for pagination - yes, oh yes.
With your current way of counting data you don't actually need other queries. as you have ALL the data already and can paginate it as well.
But of course it will pollute all the memory soon. So, if you want to get a count of rows from database, get the very count: run the same query but instead of SELECT * make it "SELECT count(*)
There are not any errors returned, that's why I am so confused
From PDO tag wiki again:
It is essential to set ERRMODE_EXCEPTION as a connection option as it will let PDO throw exceptions on connection errors. And this mode is the only reliable way to handle PDO errors.

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;

if field is empty, return all results

I'm working at a search script at the moment, but I have a little problem. I'm using the following query:
mysql_query("SELECT * FROM boeken WHERE
titel LIKE '%".$titel."%' AND
categorie_id = '".$categorie."' AND
auteurs LIKE '%".$auteurs."%' AND
jaar_copyright = '".$jaar_copyright."'
AND ontwerp_groep = '".$ontwerp_groep."'");
For example, when I search for 'categorie_id' = '5', and leave the other fiels empty, I want to get every row that has categorie_id = 5. No matter what the other fields are.
What it does is the following: I get every row that has categorie_id = 5, but where the title is empty, where the 'jaar_copyright' is empty, etc. etc.
How can I fix this the way I want?
<?php
$query = "SELECT * FROM boeken WHERE";
$n = 0;
$makeAnd = "";
foreach($_POST as $key=>$value){
if($value != '' && $value != 'submit'){
if($n != 0){$makeAnd = " AND";}
if(!is_numeric($value)){
$query .= "$makeAnd `$key` LIKE '%$value%'";
} else {
$query .= "$makeAnd `$key` = '$value'";
}
$n++;
}
}
print $query;
?>
In this way you can filter out empty values. If other values are posted to $_POST make sure to filter them out in the "if($value !=" part.
Why not just build a query based on vars? That way they're not included in the query unless the var is populated. I don't know what your variables like $titel actually are, so I just say if they're not blank. This should obviously be set towhatever is applicable. Not null, isset, etc. and always escape with something like mysql_real_escape_string()
$titel_where = "";
if($titel != '')
$title_where = "AND titel LIKE '%".$titel."%'";
$auteurs_where = "";
if($auteurs_where != "")
$auteurs_where = "AND auteurs LIKE '%".$auteurs."%'";
$jaar_copyright_where = "";
if($jaar_copyright != '')
$jaar_copyright_where = "AND jaar_copyright = '".$jaar_copyright."'";
$ontwerp_groep_where = "";
if($ontwerp_groep != '')
$ontwerp_groep_where = "AND ontwerp_groep = '".$ontwerp_groep."'";
mysql_query("SELECT * FROM boeken WHERE
categorie_id = '".$categorie."'
$titel_where
$auteurs_where
$jaar_copyright_where
$ontwerp_groep_where
");
mysql_query("SELECT * FROM boeken WHERE
( '".$categorie."' = 5 AND
categorie_id = 5
) OR
( titel LIKE '%".$titel."%' AND
categorie_id = '".$categorie."' AND
auteurs LIKE '%".$auteurs."%' AND
jaar_copyright = '".$jaar_copyright."' AND
ontwerp_groep = '".$ontwerp_groep."'
)");
For each criteria, you need to add a second evaluation for a blank parameter value:
(categorie_id = '".$categorie."' OR '".$categorie."' = '') AND ...
This way you cover both cases of an empty or a populated parameter.
EDIT:
Sample query as it would appear in SQL.
Assume you pass in a $categorie of 5 and no other parameters:
SELECT * FROM boeken WHERE
(titel LIKE '%%' OR '' = '' )AND
(categorie_id = '5' OR '5' = '') AND
(auteurs LIKE '%%' OR '' = '') AND
...
If they get passed in as NULL then do a NULL comparison instead of an empty string comparison.
You should check what field is set in code, and then only add that part to your query. for instance:
if(isset($_POST['categorie_id'])){
$where = " categorie_id = '".$categorie."' ";
}elseif(...){
....
}
Well, you get the point, you can make it a bit neater probably, depending on the format of your form/POST etc, but that's the idea. Just figure out WHAT you know, and then push it in the SQL.
I'm at work, so no long stories possible, but you should be able to figure it out with this:
foreach($_POST as $key=>$item){
if($value != ''){
$yourField = $key;
$yourValue = $item;
}
}
//PERFORM SANITY CHECKS!
//MAYBE USE PDO etc? (but that's another thing)
//SAVE them in 2 new variables used below:
$query = "SELECT * FROM boeken WHERE `$sanitizedField` = '$sanitizedValue'";

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