SQL Like Statement with multiple WHERE clauses - mysql

I am having an issue getting this to work. I have multiple WHERE statements that need to happen based on conditional information from the search query. Within there I can't seem to get the LIKE statements to work.
In the database the STREET_NUM & STREET_NAME are in different rows. I am using one input field to check against called $address
I am also struggling with getting the MIN & MAX to work.
Here is the Query:
$sql = "SELECT * FROM arc_property_res WHERE ( arc_property_res.STATUS = 'Active'";
if(!empty($_GET['city'])){
// City only query!
$sql .= "AND arc_property_res.CITY = '{$_GET['city']}'";
}
if(!empty($_GET['neighborhood'])){
// Hood only query!
$sql .= "AND arc_property_res.SUBDIVISION = '{$_GET['neighborhood']}'";
}
if(!empty($_GET['mls-number'])){
// MLS only query!
$sql .= "AND arc_property_res.MLS_ACCT = '{$_GET['mls-number']}'";
}
if(!empty($_GET['min-price']) && !empty($_GET['max-price'])){
// MIN AND MAX only query!
$sql .= "AND arc_property_res.LIST_PRICE = MIN('{$_GET['min-price']}') MAX('{$_GET['max-price']}')";
}
if(!empty($_GET['num-of-beds'])){
// BEDS only query!
$sql .= "AND arc_property_res.BEDROOMS = '{$_GET['num-of-beds']}'";
}
if(!empty($_GET['num-of-baths'])){
// BATHS only query!
$sql .= "AND arc_property_res.BATHS_FULL = '{$_GET['num-of-baths']}'";
}
if(!empty($_GET['mls-number'])){
// BATHS only query!
$sql .= "AND arc_property_res.MLS_ACCT = '{$_GET['mls-number']}'";
}
if(!empty($_GET['address'])){
$sql .= "AND arc_property_res.STREET_NUM LIKE '%{$_GET['address']}'";
$sql .= "OR arc_property_res.STREET_NAME LIKE '{$_GET['address']}%'";
}
$sql .= ") ORDER BY {$orderby}{$price_order}{$comma}{$list_date}";

I think all you need are some parentheses around the arc_property_res.STREET_NUM. Further, I would recommend you add some spaces around each line in your entire code so that you don't get syntax errors.
if(!empty($_GET['address'])){
$sql .= " AND (arc_property_res.STREET_NUM LIKE '%{$_GET['address']}' ";
$sql .= " OR arc_property_res.STREET_NAME LIKE '{$_GET['address']}%') ";
}

In addition to the obvious "Bobby Tables" issue that your query has, the problem at hand is that you do not insert a space in front of AND. This results in queries that look like this:
AND arc_property_res.BEDROOMS =3AND arc_property_res.BATHS_FULL =2
Note that there is no space between 3 and AND - a syntax error.
You should look into parametrizing your queries, and modifying it in a way that ignores the parameters that have been set to NULL.
SELECT * FROM arc_property_res WHERE ( arc_property_res.STATUS = 'Active'
AND (arc_property_res.CITY = #cityParam OR #cityParam is NULL)
AND (arc_property_res.SUBDIVISION = #subdiv OR #subdiv is NULL)
...
)
This modification would let you keep the query the same regardless of the number of parameters that were actually set, get you the same results, taking pretty much the same time.

$sql .= "AND arc_property_res.LIST_PRICE = MIN('{$_GET['min-price']}') MAX('{$_GET['max-price']}')";
The min and max functions are for when you want to get the min and max of a field in your database.
What you want is to compare the list price to see if it falls in between the min and max values supplied by the user.
$sql .= " AND arc_property_res.LIST_PRICE >= '{$_GET['min-price']}' AND arc_property_res.LIST_PRICE <= '{$_GET['max-price']}'";

Related

Writing mysql query with two variable conditions with prepare statement and bind param [duplicate]

I need to change this query to use a prepared statement. Is it possible?
The query:
$sql = "SELECT id, title, content, priority, date, delivery FROM tasks " . $op . " " . $title . " " . $content . " " . $priority . " " . $date . " " . $delivery . " ORDER BY " . $orderField . " " . $order . " " . $pagination . "";
Before the query, there's code to check the POST variables and change the content of variables in the query.
//For $op makes an INNER JOIN with or without IN clause depending on the content of a $_POST variable
$op = "INNER JOIN ... WHERE opID IN ('"$.opID."')";
//Or
$op = "INNER JOIN ... ";
//For $title (depends of $op):
$title = "WHERE title LIKE'%".$_POST["title"]."%'";
//Or
$title = "AND title LIKE'%".$_POST["title"]."%'";
//For $content:
$content = "AND content LIKE '%".$_POST["content"]."%'";
//For $priority just a switch:
$priority = "AND priority = DEPENDING_CASE";
//For $date and $delivery another switch
$d = date("Y-m-d", strtotime($_POST["date"]));
$date = "AND date >= '$d' 00:00:00 AND date <= '$d' 23:59:59";
//Or $date = "AND date >= '$d' 00:00:00";
//Or $date = "AND date <= '$d' 23:59:59";
//For $orderField
$orderField = $_POST["column"];
//For $order
$order= $_POST["order"];
//For $pagination
$pagination = "LIMIT ".$offset.",". $recordsPerPage;
How I could do this query using prepared statement?
The query could be more static but this means to make different prepared statements and execute it depending of $_POST checks.
It depends on many variables because this query show results in a table that contains search fields and column to order.
A full example of query would be like this (depending of $_POST checks):
SELECT id, title, content, priority, date, delivery FROM tasks INNER JOIN op ON task.op = op.opId WHERE op IN (4851,8965,78562) AND title LIKE '%PHT%' AND content LIKE '%%' AND priority = '2' ORDER BY date DESC LIMIT 0, 10
An excellent question. And thank you for moving to prepared statements. It seems that after all those years of struggle, the idea finally is starting to take over.
Disclaimer: there will be links to my own site because I am helping people with PHP for 20+ years and got an obsession with writing articles about most common issues.
Yes, it's perfectly possible. Check out my article, How to create a search filter for mysqli for the fully functional example.
For the WHERE part, all you need is to create two separate arrays - one containing query conditions with placeholders and one containing actual values for these placeholders, i.e:
WHERE clause
$conditions = [];
$parameters = [];
if (!empty($_POST["content"])) {
$conditions[] = 'content LIKE ?';
$parameters[] = '%'.$_POST['content ']."%";
}
and so on, for all search conditions.
Then you could implode all the conditions using AND string as a glue, and get a first-class WHERE clause:
if ($conditions)
{
$where .= " WHERE ".implode(" AND ", $conditions);
}
The routine is the same for all search conditions, but it will be a bit different for the IN() clause.
IN() clause
is a bit different as you will need more placeholders and more values to be added:
if (!empty($_POST["opID"])) {
$in = str_repeat('?,', count($array) - 1) . '?';
$conditions[] = "opID IN ($in)";
$parameters = array_merge($parameters, $_POST["opID"]);
}
this code will add as many ? placeholders to the IN() clause as many elements in the $_POST["opID"] and will add all those values to the $parameters array. The explanation can be found in the adjacent article in the same section on my site.
After you are done with WHERE clause, you can move to the rest of your query
ORDER BY clause
You cannot parameterize the order by clause, because field names and SQL keywords cannot be represented by a placeholder. And to tackle with this problem I beg you to use a whitelisting function I wrote for this exact purpose. With it you can make your ORDER BY clause 100% safe but perfectly flexible. All you need is to predefine an array with field names allowed in the order by clause:
$sortColumns = ["title","content","priority"]; // add your own
and then get safe values using this handy function:
$orderField = white_list($_POST["column"], $sortColumns, "Invalid column name");
$order = white_list($_POST["order"], ["ASC","DESC"], "Invalid ORDER BY direction");
this is a smart function, that covers three different scenarios
in case no values were provided (i.e. $_POST["column"] is empty) the first value from the white list will be used, so it serves as a default value
in case a correct value provided, it will be used in the query
in case an incorrect value is provided, then an error will be thrown.
LIMIT clause
LIMIT values are perfectly parameterized so you can just add them to the $parameters array:
$limit = "LIMIT ?, ?";
$parameters[] = $offset;
$parameters[] = $recordsPerPage;
The final assembly
In the end, your query will be something like this
$sql = "SELECT id, title, content, priority, date, delivery
FROM tasks INNER JOIN ... $where ORDER BY `$orderField` $order $limit";
And it can be executed using the following code
$stmt = $mysqli->prepare($sql);
$stmt->bind_param(str_repeat("s", count($parameters)), ...$parameters);
$stmt->execute();
$data = $stmt->get_result()->fetch_all(MYSQLI_ASSOC);
where $data is a conventional array contains all the rows returned by the query.

dividing database table data into two but what if count is odd

I want top half and bottom half of data of one table I am using queries which works fine when count is even
select count(*) from reviews
select * from reviews limit count/2
select * from reviews offset count/2
but these queries fails when count is odd
kindly give any solutions
php code
public function getdatedata($data,$data1){
if(empty($data) && empty($data1) ) return false;
$data1 = $data1/2;
$empty='';
$sql = "SELECT ";
$sql .= $this->reviews.".*";
$sql .= " FROM ".$this->reviews;
$sql .= " WHERE DATE(reviews_date) = '" . $data . "' LIMIT CEIL(". $data1.")";
$result = $this->db->query($sql);
if($result->num_rows > 0){
return $result;
} else
{ return $empty ;}
}
You can use CEIL to round the result:
select count(*) from reviews
select * from reviews limit CEIL(count/2)
select * from reviews offset CEIL(count/2)
You can also use FLOOR or ROUND, whatever you like.

MYSQL query omitting deleted

I have a column in my MySQL database for deleted values are usually 0 or 1. Usually when doing searches I omit the deleted by doing something like "and deleted = "0"" but I cant figure out how to get this query below to omit my deleted column. any ideas would be appreciated thanks!
$query = "SELECT Status, COUNT(Status) FROM Assets GROUP BY Status";
$result = mysql_query($query) or die(mysql_error());
// Print out result
while($row = mysql_fetch_array($result))
{
echo "". $row['COUNT(Status)'] ." systems ". $row['Status'];
echo ", ";
}
This should work:
$query = "SELECT Status, COUNT(Status) FROM Assets WHERE Assets.deleted = 0 GROUP BY Status";
Also, you should use mysqli or PDO rather than mysql (the php mysql library is obsolete).

how would I change this over to do a full text search instead of LIKE?

after some researching I put this code together to search a mysql table in the db. while it works fine, it limit itself to match the words exactly as the user enters it. anyone know how to make it so that it matches my some sort of relevancy? I have been reading about the full text search but I cant really seem to grasp it.
for example, if you search for 'unanswered questions' in two fields, I want to be able to get result like that include the searched word(s) in any string that it show up in, and list it according to relevancy, like so (search results example output):
- unanswered questions
- answered questions
- answer question
- unanswered questions
- unanswered questions
- questions
- answer
$k = trim ($_GET['search']);
$i = "";
$terms = explode (" ", $k);
$query = "SELECT * FROM table1 WHERE ";
foreach ($terms as $each){
$i++;
if ($i == 1)
$query .= "fld_title LIKE '%$each%' OR fld_keyword LIKE '%$each%' ";
else
$query .= "OR fld_title LIKE '%$each%' OR fld_keyword LIKE '%$each%' ";
}
// connect
include_once "connect.php"; //connect 2 db
$query = mysql_query($query);
$numrows = mysql_num_rows ($query);
if ($numrows > 0){
while ($row = mysql_fetch_assoc ($query)){
//
//
// echo out something here
//
//
}
}else
{
echo "No results found for <b>$k</b>";
}
to do a fulltext search you have to:
Create a Fulltext index in the table (note the fields can't be BLOB)
ALTER TABLE tablename ADD FULLTEXT(field1, field2,...);
in your case:
ALTER TABLE table1 ADD FULLTEXT(fld_title, fld_keyword);
in php change
$k = trim ($_GET['search']);
$i = "";
$terms = explode (" ", $k);
$query = "SELECT * FROM table1 WHERE ";
foreach ($terms as $each){
$i++;
if ($i == 1)
$query .= "fld_title LIKE '%$each%' OR fld_keyword LIKE '%$each%' ";
else
$query .= "OR fld_title LIKE '%$each%' OR fld_keyword LIKE '%$each%' ";
}
for
$k = trim ($_GET['search']);
$query="SELECT * FROM table1 WHERE MATCH(fld_title, fld_keyword) AGAINST ('".$k."')";
if you want to see the relevancy of the results:
$query="SELECT *, MATCH(fld_title, fld_keyword) AGAINST ('".$k."') as relevancy FROM table1 WHERE MATCH(fld_title, fld_keyword) AGAINST ('".$k."')";
The MATCH-AGAINST returns a number: 0 for no match or other depending on matching.
You can "order by relevancy", change the query for make more relevant the search... MATCH(fld_title, fld_keyword) AGAINST ('".$k."') > 0.5
Only one problem: the AGAINST part ($k for you) must be greater than 3 characters.

mysql and or query run together

I need to make a search engine where a user can search by name,course,member,year(text field) from the table fsb_profile fields are profile_name,profile_course,profile_member,profile_year
search will be with any one field
or
search will be with all the field
or
search will be with more than one field
-How it is possible by using only one query??
i am making the code like:-
$query="select * from fsb_profile
where profile_name = '".$_REQUEST['name']."'
and profile_member= '".$_REQUEST['type']."'
and profile_year= '".$_REQUEST['year']."'
and profile_course='".$_REQUEST['course']."'
or profile_name = '".$_REQUEST['name']."'
or profile_member= '".$_REQUEST['type']."'
or profile_year= '".$_REQUEST['year']."'
or profile_course='".$_REQUEST['course']."'";
-but it is not working?
try this query. using this query you can extract details using the combination of search factors
$query="select * from fsb_profile
where profile_name = '".$_REQUEST['name']."'
or profile_member= '".$_REQUEST['type']."'
or profile_year= '".$_REQUEST['year']."'
or profile_course='".$_REQUEST['course']."'";
If I understand you correctly, you want to search so that either all the fields match or that at least two fields match?
In that case I'd try the following:
$query="select * from fsb_profile
where
(
profile_name = '".$_REQUEST['name']."'
and profile_member= '".$_REQUEST['type']."'
and profile_year= '".$_REQUEST['year']."'
and profile_course='".$_REQUEST['course']."'
)
OR
(
(
profile_name = '".$_REQUEST['name']."'
AND
(
profile_member= '".$_REQUEST['type']."' OR
profile_year= '".$_REQUEST['year']."' OR
profile_course='".$_REQUEST['course']."'"
)
)
OR
(
profile_member= '".$_REQUEST['type']."'
AND
(
profile_year= '".$_REQUEST['year']."' OR
profile_course='".$_REQUEST['course']."'"
)
)
OR
(
profile_year= '".$_REQUEST['year']."' AND
profile_course='".$_REQUEST['course']."'"
)
)
This returns all sets where either all criteria match or a combination of at least two other criteria matches. I didn't try this really, but that's what I'd start off with.
First off, I would advise you to sanitize your input data. You should NEVER put user-entered data into an SQL query without checking it; that's just asking for trouble.
As for your question, it seems like you're having some trouble with the logic (ANDs and ORs) in your statement. With the statement you are using, you will get all records that match all four fields entered in the search engine, as well as all records that match ANY of the four fields entered. It might be best for you to just construct the query string on the fly, something like:
$arr = sanitize_data($_REQUEST);
$query = "select * from fsb_profile ";
$count = 0;
if ( isset($arr['name']) ) {
$query .= (($count > 0)?"and":"where")." profile_name = '".$arr['name']."' ";
count++;
}
if ( isset($arr['type']) ) {
$query .= (($count > 0)?"and":"where")." profile_member = '".$arr['type']."' ";
count++;
}
if ( isset($arr['year']) ) {
$query .= (($count > 0)?"and":"where")." profile_year = '".$arr['year']."' ";
count++;
}
if ( isset($arr['course']) ) {
$query .= (($count > 0)?"and":"where")." profile_course = '".$arr['course']."' ";
count++;
}
You need to add some If statements to only include search criteria if the information is filled in.
$query = "select * from fsb_profile"<br />
$subquery = ""<br />
If($_REQUEST['name') != "") {<br />
if($subquery == "") $subquery = "where "<br />
else $subquery .= "and "<br />
<br />
$subquery .= "profile_name = '" . $_REQUEST['name']<br/>
}
$query .= $subquery
You could continue to do that for all the items. Note that you can use a for statement and I would HIGHLY recommend parameterizing the search string to prevent SQL injection attacks. I have only include some of the code here for brevity.
This will search on ALL the criteria that is specified to find a result.