tags:

views:

96

answers:

2

I'd like to create a query in MySQL that has an optional value. When the value is specified the query is filtered by that value, when the value is not all rows are returned. Here's the idea:

public function doQuery($item = 'ANY_VALUE') {
  $query = "SELECT * FROM table WHERE item = ?";
  db->fetchAll($query,array($item))
  ...
}

doQuery(); // Returns everything
doQuery($item='item1'); // Returns only rows where item = 'item1'

Is there an easy way to do this without creating two query strings depending on the value of $item?

+3  A: 

As far as I know, no such "any" placeholder exists.

If you can use LIKE, you could do

SELECT * FROM table WHERE item LIKE '%'

if you can append a condition, you could nullify the item clause like this:

SELECT * FROM table WHERE item = ? OR 1=1

(won't work in your example though, because you are passing "item" as a parameter)

That's all the options I can see - it's probably easiest to work with two queries, removing the WHERE clause altogether in the second one.

This would probably work, but I*m not sure whether it's a good idea from a database point of view.

public function doQuery($item = 'ANY_VALUE') {
  $query = "SELECT * FROM table WHERE item = ? OR 1 = ?";
  db->fetchAll($query,array($item, ($item == 'ANY_VALUE' ? 1 : 0))
  ...
}
Pekka
Interesting ideas. The LIKE clause idea could work, but I think it will hurt performance. Appending another where clause would require string manipulation of the query which I wanted to avoid. If I wanted to go down that route, then I could just add the 'item = ?' clause directly to the query string...
Extending second example:SELECT * FROM table WHERE item = ? OR 1=?Put 0 in the second parameter if you want specific rows, or 1 if you want all
Mchl
I *think* that MySQL will short circuit a `LIKE '%'` statement into `1 = 1`... Try it (and I doubt it'll hurt performance much even if it's not a short circuit, since you'd need a full table scan anyway)...
ircmaxell
@Mchl that was what I had in my last revision (Now restored). I was worried about performance, but on second thought, the query optimizer will probably take care of it.
Pekka
@Pekka: Im pretty sure optimiser will deal with it great. AFAIR `x OR 1` is always optimised to `1` and `x OR 0` is optimised to `x`.
Mchl
+1  A: 

There's really no reason to do this with one query. Running the query with no WHERE clause makes it explicit that you want to return all rows. Running it with a WHERE clause makes it explicit that you want to filter the rows.

mwittrock
The actually query I'm running is much more complicated than the example I gave. Following the DRY principle, I don't want to have to maintain two copies of what is essentially the same query (plus or minus one where clause).
If I understand you correctly, you can still construct your query in one place, branching only on whether your $item parameter has a value. Wouldn't consider that a DRY violation.
mwittrock
@gerdemb, if one query has a WHERE condition, and another doesn't, by no stretch of the imagination can they be considered 'essentially the same query'. It is a big mistake to assume that because the text of two different queries is similar that the semantics of the two queries are similar.
Brian Hooper
@Brian Perhaps I over simplified my example. My actually query is over ten lines long including two sub-queries and has a series of WHERE clauses. The only difference is the addition of one more clause to filter by item. For my purposes both queries are very similar.
@gerdemb, if that's so, you are quite right. I hope I was not discourteous. This is a pet peeve of mine, having worked in a management context that thought that if you only 'had to change a couple of lines' that the result was the same and it would only take 'a few minutes'.
Brian Hooper
Regardless of the size of the actual query, conditionally adding the extra clause makes your intent clear IMO, whereas a SQL trick can easily obscure your intent.
mwittrock