Using 'case' in ORDER BY (MySQL) - mysql

I'm working in a procedure that returns a huge select where I wan't define how it is order.
I wan't choose one of three fields and if it will be ascending or descending, if none of the three options was define, it returns by default the first field in descending
this way
ORDER BY
CASE option1
WHEN 0 THEN
CASE option2
WHEN 0 THEN firstField DESC
WHEN 1 THEN firstField ASC
END
WHEN 1 THEN
CASE option2
WHEN 0 THEN secondField DESC
WHEN 1 THEN secondField ASC
END
WHEN 2 THEN
CASE option2
WHEN 0 THEN thirdField DESC
WHEN 1 THEN thirdField ASC
END
ELSE
firstField DESC
END
END;
Of course, this didn't work... mysql acuses errors in words 'DESC' and 'ASC', how can I make this works??

In order to do this, you have to move the DESC/ASC to outside the case as they come after the expression.
You should also separate the fields. In a CASE statement if the fields have different datatypes, they will be converted into one that fits all (usually VARCHAR) and this can mess up the ordering.
You could do something like:
ORDER BY CASE WHEN option1=0 AND option2=0 THEN firstField END DESC,
CASE WHEN option1=0 AND option2=1 THEN firstField END ASC,
CASE WHEN option1=1 AND option2=0 THEN secondField END DESC,
CASE WHEN option1=1 AND option2=1 THEN secondField END ASC,
CASE WHEN option1=2 AND option2=0 THEN thirdField END DESC,
CASE WHEN option1=2 AND option2=1 THEN thirdField END ASC,
firstField DESC
Each case will return NULL for all rows when not applicable and thus have the same value. In fact the first case is unnecessary as it will be caught by the default, but I have included it for clarity. This may result in a hugely expensive ordering process however!
I think I'd much rather dynamically build the SQL and I'd use an array of allowed ordering values to keep it secure.

Related

MySQL Proc OrderBy Case Not Allowing More Than One Column

I have a proc that needs to order the query by different fields depending on a parameter. To accomplish this I have created a simple case statement for my ORDER BY command which works great until I add a second sort field. I'm sure it's just a syntax issue, but I can't seem to find anything on this issue.
ORDER BY
CASE _sort
WHEN 'random' THEN RAND()
WHEN 'latest' THEN u.updated, ut.sort
WHEN 'alpha' THEN u.pageTitle, ut.sort
ELSE ut.sort
END
ASC
LIMIT _limit;
Adding the , ut.sort to each WHEN is what throws the error. When removed the proc works fine.
ORDER BY
CASE _sort WHEN 'random' THEN RAND()
WHEN 'latest' THEN u.updated
WHEN 'alpha' THEN u.pageTitle
ELSE 1
END, ut.sort

MySQL: How to use CASE for ORDER BY clause

I have a stored procedure that must return a table after filtering rows based on inputs. Two of the inputs are sort_column and sort_dir. The query must ORDER BY sort_column in the sort_dir direction(ASC or DESC).
I have tried the following queries but in vain. The queries below have been simplified to only contain the relevant clauses. The other filters work correctly with no issues.
SELECT * FROM table ORDER BY sort_column sort_dir
SELECT * FROM table ORDER BY CASE sort_column
WHEN 'col1' THEN col1_name
WHEN 'col2' THEN col2_name END
CASE sort_dir WHEN 'asc' THEN ASC
ELSE DESC END
I concatenated the 2 inputs to 1 in the format _ and tried this:
SELECT * FROM table ORDER BY CASE sort_input
WHEN 'col1_asc' THEN col1_name ASC
WHEN 'col1_desc' THEN col1_name DESC
WHEN 'col2_asc' THEN col2_name ASC
WHEN 'col2_desc' THEN col2_name DESC END
I always get error #1064. It is different in each of the above cases but always points to the 'CASE' part. This is the error for option number 2 mentioned above
##1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'WHEN 'col1' THEN col1_name END CASE 'asc' WHEN 'desc' THEN DESC ELSE ' at line 4
The problem doesn't seem to be the column name. It is the sort direction that isn't working. If I try each of the above options without the 'ASC' and 'DESC' parts, there is no problem.
Am I doing anything wrong here?
Is there a better way to go about this apart from CASE?
MySQL version: 5.6
The best approach is multiple cases:
ORDER BY (CASE WHEN sort_input = 'col1_asc' THEN col1_name END) ASC,
(CASE WHEN sort_input = 'col1_desc' THEN col1_name END) DESC,
(CASE WHEN sort_input = 'col2_asc' THEN col2_name END) ASC,
(CASE WHEN sort_input = 'col2_desc' THEN col2_name END) DESC,
This may seem verbose. But, remember that CASE is an expression that returns a single value. Hence you cannot include ASC and DESC as part of the THEN.
Also important is the issue of data types. The SQL compiler decides on a single type for CASE expression. This can cause unexpected issues when the columns have different types.
The simplest solution is just to use multiple CASE expressions.

Conditional SQL ORDER BY

I've got a polymorphic table that needs to be ordered, but the column to use for ordering depends on the type field of the table. Something like this:
ORDER BY CASE WHEN type=FOO THEN (table.last_name, table.first_name) ELSE table.name END
However, this doesn't work, can anybody point me in the right direction, I'm trying to say (in psuedocode)
IF type is FOO sort by last_name, first_name ASC OTHERWISE sort by name ASC
Could be you need a case for each column
ORDER BY CASE WHEN type=FOO THEN (table.last_name) ELSE table.name END,
CASE WHEN type=FOO THEN (table.first_name) ELSE null END
You need to specify it with two fields:
ORDER BY
CASE WHEN type=FOO THEN table.last_name ELSE table.name END,
CASE WHEN type=FOO THEN table.first_name ELSE '' END

MySQL ordering by a particular column value with a secondary order by another column's date

I have a table with the following columns in it:
status
scheduled_start
I would like to sort it to show rows with the status set to "Needs Attention" first, but I want a secondary sort by scheduled_start in ASC order.
Doing:
SELECT `tickets`.* FROM `tickets` ORDER BY CASE status WHEN 'Needs Attention' THEN 0 ELSE 1 END AND scheduled_start ASC
Will produce the rows sorted by status = Needs Attention, but the secondary sort by scheduled start is not working.
Any ideas?
You have an unnecessary "AND" in the ORDER BY clause. Try replacing it with a comma instead:
SELECT `tickets`.*
FROM `tickets`
ORDER BY
CASE status WHEN 'Needs Attention' THEN 0 ELSE 1 END,
scheduled_start ASC
Try this:
SELECT `tickets`.* FROM `tickets` ORDER BY CASE WHEN `status` = 'Needs Attention' THEN 0 ELSE 1 END ASC, scheduled_start ASC
Order by clause is not a condition, it is a list of fields and expressions you want to sort on, so separate them by commas, not an and:
.... order by expression1, field1

MySQL ORDER BY, use column mod_time, but if mod_time is 0, use column create_time

I want to order results based on two columns, mod_time and create_time.
I want the most recent to be present. At the moment I have
ORDER BY pr.mod_time DESC, pr.create_time DESC
This breaks if the item has not modified, in which case mod_time is 0 and only the create_time is set. This effectively puts anything with a mod_time of 0 to the end of the ordering even if the create_time is greater than any other mod_time.
I hope that makes sense.
Is there a way I can use ORDER BY to do this?
Thanks, Jake
You could use this:
ORDER BY CASE WHEN pr.mod_time = 0 THEN pr.create_time
ELSE pr.mod_time
END DESC, pr.create_time DESC
Or perhaps this simpler version is want you want, assuming an item will never be modified before it is created:
ORDER BY GREATEST(pr.mod_time, pr.create_time) DESC, pr.create_time DESC
Note that these queries won't be able to use an index, if any.
I'm not sure if this is what you mean, but I'll offer it in case:
Just switch your ORDER BY around:
ORDER BY pr.create_time DESC, pr.mod_time DESC
This will cause it to sort by create_time first.
A side note: You could set mod_time at create time, such that a created item was 'modified' (created) at the same time as create_time. This probably depends on what else is going on in your system though.
Add IFNULL(pr.create_time, pr.mod_time) as one of the selected columns.
Specify the position of the IFNULL in the ORDER BY.