Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MySQL order by with condition

There is the orders table with columns: status, created_at Status column having values: new, processing, other.

The issue is to select all orders, first of all with status new after that with status processing, after that all others. New and processing orders should be sorted by created_at ascending order, all other orders sorted by created_at descending order. I tried many different approaches, but stuck with each one.

For example tried combine with union two selects, but it turned out that union ignore selecting order in internal query.

Or other variant:

SELECT orders.status, orders.created_at FROM `orders`  ORDER BY status =     'new' DESC, status = 'processing' DESC,
CASE 
  WHEN (orders.status='new' or orders.status='processing') 
  THEN -created_at 
  ELSE created_at
END;

Doesn't work too.

like image 208
greenif Avatar asked Sep 19 '15 16:09

greenif


People also ask

Can I use ORDER BY in with clause?

@ric in Firebird you can put an order by in a with clause, the effects are just not guaranteed (the sort might be retained when no other steps in the query plan cause a sort).

Is ORDER BY a clause in MySQL?

Answer: ORDER BY is a clause that is typically used along with SELECT queries in MySQL and is used to return the result set sorted in the given order against the given column or field in the table.

Can we use ORDER BY with WHERE clause in SQL?

You can use the WHERE clause with or without the ORDER BY statement. You can filter records by finite values, comparison values or with sub-SELECT statements.

Can I use ORDER BY before the WHERE condition?

The ORDER BY clause is used to get the sorted records on one or more columns in ascending or descending order. The ORDER BY clause must come after the WHERE, GROUP BY, and HAVING clause if present in the query. Use ASC or DESC to specify the sorting order after the column name.


2 Answers

You can use this:

SELECT orders.status, orders.created_at
FROM `orders`
ORDER BY
  status='new' DESC,
  status='processing' DESC,
  CASE WHEN status IN ('new', 'processing') THEN created_at END ASC,
  CASE WHEN status NOT IN ('new', 'processing') THEN created_at END DESC

Please have a look at this fiddle. When status is in ('new', 'processing') the first case when will return the created date that will be ordered ascending, or null otherwise. When status is not in ('new', 'processing') the second case when will return the created date that will be in descending order.

like image 126
fthiella Avatar answered Sep 21 '22 16:09

fthiella


This is working in Oracle. Please check if it works in MySQL too. Idea is to convert the created_at in desc order in case statement. multiplying -1 is not doing it. So give it a try. Also please replace sysdate to its mysql equivalent.

       select  orders.status, orders.created_at FROM orders
       ORDER BY
        CASE 
        WHEN (orders.status='new' or orders.status='processing') 
        THEN created_at end,
        case when orders.status='other' then (sysdate - created_at) 
      END;

Output

      STATUS        CREATED_AT          
      processing    20-AUG-2015 22:11:24
      processing    30-AUG-2015 22:11:24
      new           30-AUG-2015 22:11:24
      new           09-SEP-2015 22:11:24
      other         10-AUG-2015 22:11:24
      other         31-JUL-2015 22:11:24
like image 24
Utsav Avatar answered Sep 23 '22 16:09

Utsav