views:

357

answers:

3

Ok, so on my site we have a filter section where a user can select to filter through games by either the game's genre or the model that the game will play on.

I'm trying to write a query that will query the database and filter it by genre if genre is the only set item, filter it by model if model is the only set item, or filter both if they're both set. I want the code to be efficient as well so if you know a good method on doing this that would be great to hear.

+1  A: 

Note, the answer below assumes the form fields contain the value that is to be queried for. Don't forget error checking, and that you'll need to validate the $_GET/$_POST variables to prevent SQL injection type hacks.

// Generally you would have a function to construct your query here:
function select($where,$orderBy){
...
}

// Then when you when you are ready to build your query

$where = "";

if($model !== 'all'){                  
  $where .= "model ='".$model."'";
  $orderBy = "model ASC";
}

if($genre !== 'all'){                  
  if(isset($model)&&($model !== 'all')){
    $where .= " AND ";
  }
  $where .= "genre <='".$genre."'";
  $orderBy = "genre ASC";
}

// Adding additional filters will look like this

if($additionalFilter !== 'all'){
  if(isset($genre)&&($genre !== 'all')||isset($model)&&($model !== 'all')){
    $where .= " AND ";
  }                  
  $where .= "additionalFilter <='".$additionalFilter."'";
  $orderBy = "additionalFilter ASC";
}

// And finally to put it all together:

select($where, $orderBy);
This can get extremely messy if he later decides he wants five or six filters instead of two.
mynameiscoffey
While your answer is shorter and could probably be used to shorten the code above, often a query that requires 5 or 6 filters will be complex enough to warrant additional logic.
+1  A: 

The best approach is to structure your database as such first:

Table 'game':
| id | title | description |
Table 'models':
| id | name | description |
Table 'genres':
| id | name | description |
Table 'game2model':
| game_id (FK to game.id) | model_id (FK to models.id) |
Table 'game2genre':
| game_id (FK to game.id) | genre_id (FK to genres.id) |

Once your DB is normalized in that way, doing your SQL filtering is extremely easy. This pseudo SQL code should get you on the right track:

[We are assuming your genres IDs are 1,2,3 and your models IDs are 10, 11 and 12].

SELECT g.id, g.name, g.description
FROM games g, games2genre gg, games2model gm
WHERE gg.game_id = g.id
AND gm.game_id = g.id
AND gg.genre_id IN (1,2,3)
AND gm.model_id IN (10,11,12)
ORDER BY g.name ASC

loginx
+2  A: 

assuming variables $genre and $model already escaped. demo code only, no security for clarity purposes.

$sqlQuery = 'select * from games where 1=1';
if ( !empty($genre) ) $sqlQuery .= " and genre=$genre";
if ( !empty($model) ) $sqlQuery .= " and model=$model";
mynameiscoffey
Don't forget to escape your inputs for security.
vincebowdren
Absolutely terrific! Simple and does exactly what I needed! Thank you! And yes, I know how to escape the inputs and secure everything.
NessDan
I'm actually having a separate problem now. Looking at my query, I can't have WHERE at the end.$sql = "SELECT * FROM appinfo ORDER BY rating_score / rating_num DESC LIMIT 5";Unless there's a way to put it at the end without it throwing out an error.
NessDan
Two options1. add another line after the ifs `$sqlQuery .= ' order by ... limit ...';`2. do all the ifs first into a variable called $sqlWhere or similar and at the end: `$sqlQuery = "select * from ... $sqlWhere order by ... limit ...";`. Whichever fits you better.
mynameiscoffey
Thanks, now everything is fine :D
NessDan