Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to make sure a record is always at the top in a given resultset in mysql?

I have a search query which yields a resultset based on input parameters and the result can be sorted (ASC/DESC) based on different parameters: price, duration etc (with pagination in place and limit of 10 records)

I now have a requirement wherein, if I have an id passed in, I'd like the corresponding record to be made to sticky at the top in the given resultset.

Lets say we have a package table like this:

Package
 - id
 - name
 - mPrice
 - vPrice
 - duration

// Searching pkg based on Price (in DESC order) where name = Thailand
sqlQuery = 
"SELECT p.id, p.name, p.mPrice, p.vPrice FROM package p 
WHERE p.name = LOWER('Thailand') 
ORDER BY (p.mPrice + p.vPrice) DESC 
LIMIT 10"

Let's assume the complete resultset is 20 records with ids 1 to 20. I'm now required to return record with id 14 to always be at the top. I came up with the following query, but this isn't working:

sqlQuery = 
"SELECT p.id, p.name, p.mPrice, p.vPrice FROM package p 
WHERE p.name = LOWER('Thailand') or p.id = 14
ORDER BY CASE 
WHEN p.id=14 then 0 
else (p.mPrice + p.vPrice) 
end DESC 
LIMIT 10"

My guess as to why this is not working: After order by clause, the resultset is sorted in descending order, which is then truncated at 10 records. The record with id=14 may not be a part of this truncated set. Is this correct ?

How do I get record with id=14 to stick at the top ?

like image 822
brainydexter Avatar asked Aug 06 '12 06:08

brainydexter


3 Answers

ORDER BY (p.id=14) DESC, (p.mPrice=p.vPrice) DESC

p.id=14 returns 1 if the condition is true, 0 otherwise, so sorting descending brings the desired row to the top.

Returning a number from a comparison is a MySQL feature, with standard SQL you would write:

ORDER BY CASE WHEN (p.id=14) THEN 0 ELSE 1 END,
         CASE WHEN (p.mPrice=p.vPrice) THEN 0 ELSE 1 END

I find this easier to read than the UNION, and it might perform better.

like image 89
Peter Lang Avatar answered Sep 27 '22 19:09

Peter Lang


Use a union to always have your package at top:

SELECT id, name, mPrice, vPrice FROM package WHERE id = 14
UNION
SELECT p.id, p.name, p.mPrice, p.vPrice FROM package p 
WHERE p.name = LOWER('Thailand') or p.id = 14
ORDER BY (p.mPrice = p.vPrice) DESC
LIMIT 9
like image 39
Matten Avatar answered Sep 27 '22 19:09

Matten


try this:

order by 
 case when p.id=14 then then (select MAX(mPrice)+1 from package ) else
(p.mPrice = p.vPrice)  end desc
LIMIT 10

Instead of (select MAX(p.mPrice)+1 from package ) you can give a constant value which would be always a maximun value, something like this

 order by 
 case when p.id=14 then then 1000000 else
(p.mPrice = p.vPrice)  end desc
LIMIT 10

which would be more effitient

like image 40
Joe G Joseph Avatar answered Sep 27 '22 20:09

Joe G Joseph