tags:

views:

89

answers:

5

I am making a search feature for a Job listing website. For that I need to first show the listings with matching titles and then the job listings with matching description. Here is the query, I am using right now:

Example:

(SELECT * FROM `jobs` WHERE title LIKE '%java%developer%') 
UNION DISTINCT 
(SELECT * FROM `jobs` WHERE description LIKE '%java%developer%')

However, I also need to sort the results by the timestamp so as to show the latest results first. Like it should give the results with matching titles sorted by timestamp and then the the listings with matching description sorted by timestamp.

+2  A: 

Try this, replace timestamp by the name of your timestamp column

(SELECT *, 1 as unionsorting FROM `jobs` WHERE title LIKE '%java%developer%' ORDER BY timestamp desc)
UNION DISTINCT
(SELECT *, 2 as unionsorting FROM `jobs` WHERE description LIKE '%java%developer%' ORDER BY timestamp desc)
ORDER BY unionsorting

But doing 2 queries is probably faster (this has to be tested)

SELECT * FROM `jobs` WHERE title LIKE '%java%developer%' ORDER BY timestamp desc
SELECT * FROM `jobs` WHERE description LIKE '%java%developer%' ORDER BY timestamp desc
radius
woulnd't the timestamp column sort would take precedence over the title > description sort?
potatopeelings
@potatopeelings Yes i misread the question and updated my answer ! Thanks for pointing this out
radius
This works nicely, but you need to change `1 as unionsorting, *` to `*, 1 as unionsorting`.
Mike
@mike: why? order is irrelevant
knittl
@knittl: The use of an unqualified `*` can produce a parsing error. Placing the `*` first, or using a table reference (`tbl.*`) solves the problem. This may only affect some MySQL versions, and it definitely affects mine (5.0.51a-24+lenny3). See [SELECT Syntax](http://dev.mysql.com/doc/refman/5.5/en/select.html), look for "Use of an unqualified".
Mike
@mike: never mattered for my cases, but i don't have a mysql installation to test right now
knittl
@knittl: It's only a problem when used with other items in the select list.
Mike
This will give some redundant results, since listings having the keywords both in the title and the description will be returned twice. Adding 1 or 2 will make the distinct irrelevant.
Chetan
I edited to add Mike advice
radius
+1  A: 

Edited: to fix...

This is a little clunky, but some variation on it will work:

SELECT title, description, timestamp_column, min(rank) from 
(
    (SELECT *, 1 as rank FROM `jobs` WHERE title LIKE '%java%developer%') 
    UNION
    (SELECT *, 2 as rank FROM `jobs` WHERE description LIKE '%java%developer%')
) x
GROUP BY title, description, timestamp_column 
ORDER BY min(rank), timestamp_column DESC

This uses the GROUP BY clause in place of DISTINCT

egrunin
the timestamp column sort would take precedence over the title > description sort, right?
potatopeelings
@potatopeelings: Fixed, I think.
egrunin
This will give some redundant results, since listings having the keywords both in the title and the description will be returned twice. Adding 1 or 2 will make the distinct irrelevant.
Chetan
@Chetan: I think I've fixed it now...
egrunin
A: 
(SELECT * FROM `jobs` A WHERE title LIKE '%java%developer%' ORDER BY A.colDateTime desc) 
UNION DISTINCT 
(SELECT * FROM `jobs` B WHERE description LIKE '%java%developer%' ORDER BY B.colDateTime desc)
VoodooChild
um... would this be consistent? http://dev.mysql.com/doc/refman/5.0/en/union.html > ...However, use of ORDER BY for individual SELECT statements implies nothing about the order in which the rows appear in the final result because UNION by default produces an unordered set of rows.
potatopeelings
oh, is this right? Can someone please confirm this as well?
VoodooChild
Yes, that's true. See [UNION Syntax](http://dev.mysql.com/doc/refman/5.0/en/union.html). Look for 'use of ORDER BY for individual SELECT statements implies nothing about the order'.
Mike
As said by others, this doesn't works since the order is changed when we do the Union
Chetan
+1  A: 
SELECT * 
FROM `jobs` 
WHERE (title LIKE '%java%developer%' OR description LIKE '%java%developer%')
ORDER BY (CASE WHEN title LIKE '%java%developer%' THEN 0 ELSE 1 END), timestamp_col DESC
andrem
isn't an END required for the CASE?
potatopeelings
yes you'r right, i missed that, thanks
andrem
+2  A: 

i would probably write the query similar to:

  select *, ((title like '%…%')*2 + (description like '%…%')) as rank
    from jobs
   where title like '%…%'
      or description like '%…%'
order by rank desc, time desc

this way, rows where both title and description match will appear first, then title-matches, then description-matches. i haven't tested it, but usually mysql does a good job converting bool to int (true: 1, false: 0)

knittl
this works, thanks a lot!
Chetan