tags:

views:

327

answers:

4

Say I have two tables: users and groups, each of which has a name. I wish to provide a 'simple search', in which the user enters text and results contain both users and groups whose names contain the text. The results must distinguish between the two types.

+3  A: 

The trick is to combine a UNION with a literal string to determine the type of 'object' returned. In most (?) cases, UNION ALL will be more efficient, and should be used unless duplicates are required in the sub-queries. The following pattern should suffice:

 SELECT "group" type, name
   FROM groups
  WHERE name LIKE "%$text%"
UNION ALL
 SELECT "user" type, name
   FROM users
  WHERE name LIKE "%$text%"

NOTE: I've added the answer myself, because I came across this problem yesterday, couldn't find a good solution, and used this method. If someone has a better approach, please feel free to add it.

Bobby Jack
+1  A: 

If you use "UNION ALL" then the db doesn't try to remove duplicates - you won't have duplicates between the two queries anyway (since the first column is different), so UNION ALL will be faster.
(I assume that you don't have duplicates inside each query that you want to remove)

hamishmcn
Thanks. Produces the same results, although I haven't tested for efficiency (yet), but what you say makes perfect sense. In reality, I'm also selecting a primary key.
Bobby Jack
+1  A: 

Using LIKE will cause a number of problems as it will require a table scan every single time when the LIKE comparator starts with a %. This forces SQL to check every single row and work it's way, byte by byte, through the string you are using for comparison. While this may be fine when you start, it quickly causes scaling issues.

A better way to handle this is using Full Text Search. While this would be a more complex option, it will provide you with better results for very large databases. Then you can use a functioning version of the example Bobby Jack gave you to UNION ALL your two result sets together and display the results.

Josef
Sure, by "simple" I guess I'm also implying (or trying to!) that these are both very small tables, and the application is such low-use that a brute-force LIKE search is perfectly acceptable. I'll edit the question to clarify this - and other points - when activity slows. Cheers.
Bobby Jack
+1  A: 

I would suggest another addition

 SELECT "group" type, name
   FROM groups
  WHERE UPPER(name) LIKE UPPER("%$text%")
UNION ALL
 SELECT "user" type, name
   FROM users
  WHERE UPPER(name) LIKE UPPER("%$text%")

You could convert $text to upper case first or do just do it in the query. This way you get a case insensitive search.

Mark Nold
The case-sensitivity of LIKE depends on the database (and maybe even the collation). I'm using MySQL, where the LIKE comparison is case-insensitive anyway.
Bobby Jack