views:

107

answers:

4

I have a simple SQL query,

SELECT * FROM phones WHERE manu='$manuf' AND price BETWEEN $min AND $max

The issue is that all of the variable fields are connected to fields that will sometimes be empty, and thus I need a way to make them match any value that their respective field could take if they are empty. I tried

$min=$_REQUEST['min_price'];
$max=$_REQUEST['max_price'];
$manuf=$_REQUEST['manufact'];
if (empty($min)){
    $min=0;}
if (empty($max)){   
    $max=900000;}
if (empty($manuf)){
    $manuf='*';}

which works ok for the numerical fields (although I don't like having to manually set limits like this), but I can't figure out how to get a universal match for the text field. I thought * would do it since it matches all row names, but apparently not. Anyone know how to do this?

+1  A: 

I am guessing that you want to make it a "filter" type query that allows the parameters to be optional? You could do something like:

SELECT 
    * 
FROM 
    Phones 
WHERE
    (manu = $manu OR manu IS NULL)
    AND (min = $min OR min IS NULL)
    AND (max = $max OR max IS NULL)

Adding the OR with the null option (you can make it an empty string or whatever) allows you to filter on any parameter passed.

You can combine this with what you have above, checking for min/max and supplying defaults for your BETWEEN clause.

David in Dakota
I think he means (price >= $min OR $min IS NULL) AND (price <= $max OR $max IS NULL). But please, PLEASE think of SQL-injection. Either prepare the statement or at least use mysql_real_escape_string() to escape the input!
Cassy
+1  A: 

Hi,

If I were you, I would cut the whole SQL into parts, and dealing with the WHERE statement.

Somethin like:

sql = "SELECT * FROM phones WHERE 1=1 "
if (not empty($manu))
    sql = sql + ' AND manu = "$manu"'
...

Regards.

ATorras
If I were you I would avoid building SQL dynamically like that all together...
Dems
Yes, but I suppose all of us know about SQL injection (as you posted after) and how to avoid them. If somebody is a lazy programmer no tool will change that.
ATorras
Fair point, but I deal with lazy programmers all the time and part of my job is to minimise their impact ;)
Dems
I don't know about SQL injection.
Elliot
Then, SERIOUSLY find out.
Dems
+1  A: 

I tend to do this by changing the logic in the SQL and passing in NULL parameters, or parameters with specific values.

WHERE manu='$manuf' AND price BETWEEN $min AND $max

=>

WHERE
    (manu='$manuf' OR '$manuf' = '*')    -- Check for "special value"
    AND (price >= $min OR $min IS NULL)  -- Check for NULL
    AND (price <= $max OR $max IS NULL)  -- Check for NULL
Dems
Note: I say I pass in parameters, you're building a string to be executed dynamically. As other have stated many times, this is quite bad practice in general, due to SQL injection attacks. Better to use a mthodology that allow parameterisation.
Dems
There's always trade-offs - your suggestion will suffer performance-wise due to OR use, which destroys sargability. SQL injections can be handled.
OMG Ponies
+1 Java have the PreparedStatement object that will _help_ you preventing the SQL injection. This sheet may help you to archieve this goal: http://www.owasp.org/index.php/SQL_Injection_Prevention_Cheat_Sheet
ATorras
Actually, most RDBMS won't loose sargability in this case. (field <= constant OR constant = constant) can be handled in the execution plan because half of the OR condition resolves to a constant itself. If it were (field <= constant OR field = constant) things would be different, but even then I would doubt all use of indexes would be lost in anything but a very primative RDBMS.
Dems
A: 

Maybe something like...

SELECT * FROM phones 
WHERE manu = coalesce(?, manu)
AND price >= coalesce(?, price) 
AND price <= coalesce(?, price)

Then pass in parameters instead of putting in the variables directly (not sure how to do that in PHP off the top of my head).

Corey