mysql - if value = 0 shorten where statement - php

I wonder if it's possible to shorten query depending on some variable value in elegant way.
For example: I have value named $var = 0 and I would like to send a query that looks like this:
$query = "SELECT id, name, quantity FROM products WHERE quantity > 100";
But whan the $var != 1 I'd like to send a query like this:
$query = "SELECT id, name, quantity FROM products WHERE quantity > 100 AND id = '$var'";
So depending on value of $var I want to execute one of queries. They differ only with last expression.
I found two possible solutions but they are not elegant and I dont like them at all.
One is made in php:
if ( $var == 0 ) {
$query_without_second_expression
} else {
$query_with_second_expression
}
Second is made in mysql:
SELECT WHEN '$var' <> 0 THEN id, name, quantity
FROM products WHERE quantity > 100 AND id = '$var' ELSE id, name, quantity
FROM products WHERE quantity > 100 END
but i dont like it - each idea doubles queries in some whay. Can I do something like this?
SELECT id, name, quantity
FROM products WHERE quantity > 100
CASE WHEN $var <> 0 THEN AND id = '$var'
It's much shorter, and adds part of query if needed. Of course real query is much more complicated and shorter statement would be really expected. Anyone has an idea?

If I understand well..
$query = "SELECT id, name, quantity FROM products WHERE quantity > 100";
if ( $var != 0 ) {
$query .= " AND id = '$var'";
}
do you like it?

You could so something like this on the SQL side:
"SELECT id, name, quantity FROM products WHERE quantity > 100 AND (id = '$var' OR '$var' = 0)
But performance could be impacted. I would suggest building the appropriate query on the PHP side.

I'm no PHP developer (it is PHP, right?), but wouldn't it be easiest to build your query from a concatenated string?
Pseudo-code:
$my_query = "SELECT id, name, quantity FROM products WHERE quantity > 100"
if ($var != 1)
$my_query = $my_query + " AND id = '$var'";
end if;
/*go ahead with your query*/

You can do this:
SELECT id, name, quantity
FROM products
WHERE 1 = 1
AND ( $q IS NULL OR quantity > $q)
AND ( $var IS NULL OR id = $var)
If you want only the first condition to run then pass $q = 100 and $var = NULL, therefore the second condition will be ignored. And for the second query pass the $q = 100 and $var = id value and you will got the your second query.

If they only differ in additional where-statements, I would probably still stay in PHP and do the following:
$conditions = array();
$conditions[] = "(quantity > 100)"
if ($var == 0)
$conditions[] = "(id = '$var')";
if (some-other-expression)
$conditions[] = "(myfield = 'foo' OR myfield = 'bar')";
$sql = "
SElECT id, name, quantity
FROM products
WHERE
";
$sql .= $conditions.join(" AND ");
/ Carsten

I would use a ternary for this:
$query = "SELECT id, name, quantity FROM products WHERE quantity > 100" . ( $var != 0 ? " AND id = '$var'" : '' );

I'm an Oracle guy, but could you use the IF() function in your constraints, e.g.:
SELECT id, name, quantity
FROM products
WHERE quantity > 100
AND id = IF('$var'=0,'%','$var');
The '%' is a wildcard that would match anything, effectively ignoring the 2nd expression.

So if you are using the
If or the CASE
Why don't you use them in your sql query.
It would be some like
if ( $var == 0 ) {
$query_without_second_expression
}
else
{
$query_with_second_expression
}
But in you sql query.
DECLARE #var int
if(#var=1)
BEGIN
query 1
END
else
BEGIN
query 2
end
I guess this will solve your problem.
But as a personal advice try to make one query. Even with the variable. We don't believe in changing standard query depending on the conditions.
Still your wish and your desire
Cheers!!

For this particular problem, go with Paper-bat's simple condition append snippet.
However, if you have entirely different where statements, consider appending the appropriate where statement to the query once you know what you want. For instance,
$query = "SELECT id, name, quantity FROM products ";
if ( $var == 0 ) {
$query .= "quantity > 100";
} elseif {
$query .= "quantity > 120 AND id = '$var'";
} elseif {
...
}
...
It all depends on your needs, but neither this or Paper-bat's solutions duplicate query code.

Related

select all rows when search parameter value is null or empty [mysql]

I am trying to use multiple search options where user can select multiple options to filter records.
When user don't select filter option(s), by default all records should be returned.
Here's my SQL query :
$query =
sprintf("SELECT * FROM users_leave_request
where leave_from >= '$leave_from'
AND leave_to <= '$leave_to'
AND leave_status = '$leave_stat'
AND user_id = '$emp_id'");
$result=$this->db->exec($query);
What I intend to do is that:
Suppose $leave_stat parameter is empty, then records for all leave_stat values should be returned.
Similarly if $emp_id is empty, records for all users should be returned.
It's somewhat like disabling that *extra AND* where condition when parameter is empty.
Can I do this with a single query or do I have to use separate queries for that?
Any help is very much appreciated. Thanks.
You can check the filter condition before the query, like this
$whrcondn="";
$whrcondn.=($leave_from)?" and leave_from > = '$leave_from'":"";
$whrcondn.=($leave_to)?" and leave_to < = '$leave_to'":"";
$whrcondn.=($leave_status)?" and leave_status = '$leave_stat'":"";
$whrcondn.=($emp_id)?" and user_id ='$emp_id'":"";
$query = sprintf("select * from users_leave_request where 1=1 $whrcondn");
look at this simple way
add this condition
if(!empty($leave_stat))
{$x='leave_status';}
else
{$x='leave_status!';}
if(!empty($leave_stat))
{$y='user_id';}
else
{$y='user_id!';}
then change leave_status and user_id by $x and $y like this :
$query = sprintf("SELECT * FROM users_leave_request
where leave_from >= '$leave_from'
AND leave_to <= '$leave_to'
AND '$x' = '$leave_stat'
AND '$y' = '$emp_id'");
$result=$this->db->exec($query);
and good luck

How to write sql query in php with if statement in WHERE

How do I write a SQL query with an if statement in the WHERE part of a query?
Here is my sql:
$sql = 'SELECT First, Second,
Third,Fifth, Status, Isik_id, Comments, Code
FROM Persons WHERE Status = 1 && Third = "'.$whoislogged.'" ORDER BY RAND() LIMIT 1';
The Third = "'.$whoislogged.'" is a word what comes from session.
If $whoislogged exists and is equal to Third then the query should be like:
$sql = 'SELECT First, Second, Third,Fifth, Status, Isik_id, Comments, Code
FROM Persons
WHERE Status = 1 && Third = "'.$whoislogged.'" ORDER BY RAND() LIMIT 1';
But if the $whoislogged dosent appear then the query should be like:
$sql = 'SELECT First, Second,
Third,Fifth, Status, Isik_id, Comments, Code
FROM Persons WHERE Status = 1 ORDER BY RAND() LIMIT 1';
So how can I put all this into one query?
You can handle it in query itself.
WHERE Status = 1 and if(Third = "'.$whoislogged.'", Third = "'.$whoislogged.'" , 1=1)
the condition part will check third is match with $whoislogged if it's true then add id as condition otherwise omit this condition.
Simply make a new variable that contains the Third statement
if ( !empty($whoislogged) ) $third = "AND Third = ". $whoislogged;
else $third = "";
$sql = 'SELECT First, Second,
Third,Fifth, Status, Isik_id, Comments, Code
FROM Persons WHERE Status = 1 '. $third .' ORDER BY RAND() LIMIT 1';
It is not the most efficient way but it works

Search query and ordering by matches with my sql

Hi am currently stuck here, been doing research on how to write a mysql statement for a flexible search for products and order them by relevance on a project am working on have seen a few but wasn't helpful please i need help on how to make it work, my current method doesn't work, here it is.
User types in search field and submits "iPad 3rd Generation".
My script breaks the string into words like so.
$termsExploded = array_unique(explode(' ', $term));
No i use php to create an sql query based on the number of words found.
$i = 0;
foreach ($termsExploded as $word) {
if (strlen($word)>1) {
if ($i == 0) {
$where_query = $where_query." name LIKE '%".$word."%'";
}
else{
$where_query = $where_query." OR name LIKE '%".$word."%'";
}
$i++;
}
}
The where query variable now looks like this.
name Like '%ipad%' Or name Like '%3rd%' Or name Like '%Generation%'
Now search for the products ids like so.
$IDs = "SELECT DISTINCT id FROM store_items WHERE".$where_query;
I now create a second where query based on the IDs returned like so
$where_query_s = null;
$i = 0;
foreach ($IDs as $result) {
$returnID = $result->id;
if ($i == 0) {
$where_query_s = $where_query_s." id = ".$returnID."";
}
else{
$where_query_s = $where_query_s." OR id = ".$returnID."";
}
$i++;
};
Now i select the products again based on the distinct IDs returned like so
$items = "SELECT * FROM store_items WHERE".$where_query_s;
Now this works to get the products but how can i sort it based on best match?
Assuming you want to order by the number of matches then build up another string as follows:-
ORDER BY IF(name Like '%ipad%', 1, 0) + IF(name Like '%3rd%', 1, 0) + IF(name Like '%Generation%', 1, 0) DESC
But this will be slow, and takes no account of indexing to improve performance nor of plural / singular (ie, it someone searches for 'flies' it won't rank 'fly' properly).
To put that more into code:-
$where_query = array();
$order_query = array();
foreach ($termsExploded as $word)
{
if (strlen($word)>1)
{
$where_query[] = " name LIKE '%".$word."%'"
$order_query[] = " IF(name Like '%".$word."%', 1, 0)"
}
}
$IDs = "SELECT DISTINCT id FROM store_items WHERE ".implode(' OR ', $where_query)." ORDER BY ".implode(' + ', $order_query)." DESC";
Arrange for your query to look like this:
select field1, field2, etc, count(*) records
from store_items
where blah blah blah
group by field1, field2, etc
order by records desc
If the table is MyISAM based or if it is InnoDB and the version is Mysql 5.6 or greater, then you can use full text search (see http://dev.mysql.com/doc/refman/5.6/en/fulltext-search.html)
effectively you want a query similar to
SELECT * FROM store_items WHERE MATCH (name) AGAINST ('iPad 3rd Generation')
ORDER BY MATCH (name) AGAINST ('iPad 3rd Generation')

Echo variable which has same name in php join

I have a mysql join which is pulling from two tables name product & cart and they're both being pulled from a variable $row_checkout
If i have to echo a certain field, i can normally go $row_checkout['cartid'] and that works fine.
However, i have a coloumn in each table which is called the same 'Status'.
How do i echo from one of the tables? I thought something like $row_checkout['cart.status'] might work but it doesnt appear to?
My database code is as follows:
$colname_checkout = "-1";
if (isset($row_booking['sessionid'])) {
$colname_checkout = (get_magic_quotes_gpc()) ? $row_booking['sessionid'] : addslashes($row_booking['sessionid']);
}
mysql_select_db($database_main, $main);
$query_checkout = sprintf("SELECT * FROM cart, productdatabase WHERE cart.productid = productdatabase.productid AND cart.status != 1 AND cart.status != 0 AND cart.sessionid = '%s' ORDER BY `name` ASC", $colname_checkout);
$checkout = mysql_query($query_checkout, $main) or die(mysql_error());
$row_checkout = mysql_fetch_assoc($checkout);
$totalRows_checkout = mysql_num_rows($checkout);
You can use alias to change a tables field name, to a name that you want.
the cart.status filter, you could make simpler, simpler by asking > 1
SELECT c.status as car_status, pro.status as pro_status
FROM cart as c, productdatabase as pro
WHERE c.productid = pro.productid AND c.status >1 AND c.sessionid = '%s'
ORDER BY `name` ASC", $colname_checkout
Seeing what you get, it will display an associative array with all names and values, that you can use to address the data
while ($row_checkout = mysql_fetch_assoc($checkout)) {
print_r($row_checkout);
}
or specific the fields:
while ($row_checkout = mysql_fetch_assoc($checkout)) {
echo $row_checkout["car_status"];
echo $row_checkout["pro_status"];
}
another comment, the mysql function is not recommended anymore. You could use MySQLi or PDO_MySQL. They are both object oriented and may need a little more time to learn.
Use alias.
Refernce :
http://www.tutorialspoint.com/sql/sql-alias-syntax.htm
$query_checkout =
sprintf("SELECT *,**cart.status AS cart_status, productdatabase.status as
pdb_status** FROM cart, productdatabase WHERE
cart.productid = productdatabase.productid AND
cart.status != 1 AND cart.status != 0
AND cart.sessionid = '%s' ORDER BY `name` ASC", $colname_checkout);

SQL query results returned, even if exact match not found

I hope this question isn't redundant. What I am trying to accomplish is have a user select a bunch of checkboxes on a page and return the closest matching records if there are no matching rows. For example:
A person checks off [x]Apples [x]Oranges [x]Pears [x]Bananas
But the table looks like this:
Apples Oranges Pears Bananas
1 1 1 null
1 1 null 1
1 1 null null
(Obviously I missed the id column here, but you get the point I think.) So, the desired result is to have those three rows still be returned in order of most matches, so pretty much the order they are in now. I'm just not sure what the best approach to take on something like this. I've considered a full text search, the levenshtein function, but I really like the idea of returning the exact match if it exists. No need for you to go at length with code if not needed. I'm just hoping to be sent in the right direction. I HAVE seen other questions sort of like this, but I still am unsure about which way to go.
Thanks!
Write a query that adds up the number of columns that matched, and sorts the rows by this total. E.g.
SELECT *
FROM mytable
ORDER BY COALESCE(Apples, 0) = $apples + COALESCE(Oranges, 0) = $oranges + ... DESC
It's easy to sort by a score...
SELECT fb.ID, fb.Apples, fb.Oranges, fb.Pears, fb.Bananas
FROM FruitBasket fb
ORDER BY
CASE WHEN #Apples = fb.Apples THEN 1 ELSE 0 END
+ CASE WHEN #Oranges = fb.Oranges THEN 1 ELSE 0 END
+ CASE WHEN #Pears = fb.Pears THEN 1 ELSE 0 END
+ CASE WHEN #Bananas = fb.Bananas THEN 1 ELSE 0 END
DESC, ID
However, this leads to a table-scan (even with TOP). The last record may be a better match than the records found so far, so every record must be read.
You could consider a tagging system, like this
Content --< ContentTag >-- Tag
Which would be queried this way:
SELECT ContentID
FROM ContentTag
WHERE TagID in (334, 338, 342)
GROUP BY ContentID
ORDER BY COUNT(DISTINCT TagID) desc
An index on ContentTag.TagId would be used by this query.
This is fairly simple, but you can just use IFNULL() (MySQL, or your DB's equivalent) to return a sum of matches and use that in your ORDER BY
// columns and weighting score
$types = array("oranges"=>1, "apples"=>1, "bananas"=>1, "pears"=>1);
$where = array();
// loop through the columns
foreach ($types as $key=>&$weight){
// if there is a match in $_REQUEST at it to $where and increase the weight
if (isset($_REQUEST[$key])){
$where[] = $key . " = 1";
$weight = 2;
}
}
// build the WHERE clause
$where_str = (count($where)>0)? "WHERE " . implode(" OR ", $where) : "";
// build the SQL - non-null matches from the WHERE will be weighted higher
$sql = "SELECT apples, oranges, pears, bananas, ";
foreach ($types as $key=>$weight){
$sql .= "IFNULL({$key}, 0, {$weight}) + ";
}
$sql .= "0 AS score FROM `table` {$where_str} ORDER BY score DESC";
Assuming that "oranges" and "apples" are selection, your SQL will be:
SELECT apples, oranges, pears, bananas,
IFNULL(apples, 0, 2) + IFNULL(oranges, 0, 2) + IFNULL(pears, 0, 1) + IFNULL(bananas, 0, 1) + 0 AS score
FROM `table`
WHERE oranges = 1 OR apples = 1
ORDER BY score DESC
Order descending by the sum of checkbox/data matches
SELECT * FROM table
ORDER BY (COALESE(Apple,0) * #apple) + (COALESE(Orange,0) * #orange) ..... DESC
where #apple / #orange represents users selection: 1 = checked, 0 = unchecked

Categories