最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

laravel - SQL ASC and DESC ordering on same column based on another column - Stack Overflow

programmeradmin2浏览0评论

I want to arrange pending orders by eta in asc order and completed orders in desc order, with all completed orders appearing at the bottom of the list. Not sure if this is possible in a single query.

Example data from orders table:

order status eta
1 pending 20-01-2025
2 complete 15-01-2025
3 ordered 28-01-2025
4 complete 16-01-2025
5 sailing 25-01-2025

I want to arrange pending orders by eta in asc order and completed orders in desc order, with all completed orders appearing at the bottom of the list. Not sure if this is possible in a single query.

Example data from orders table:

order status eta
1 pending 20-01-2025
2 complete 15-01-2025
3 ordered 28-01-2025
4 complete 16-01-2025
5 sailing 25-01-2025

I would like the above data to be displayed as follows:

order status eta
1 pending 20-01-2025
3 sailing 25-01-2025
5 ordered 28-01-2025
4 complete 16-01-2025
2 complete 15-01-2025

in the above result only the eta column is ordered, where all 'complete' orders at the bottom

I am using Laravel to build my app, with a Postgres backend, but I am sure any SQL solution will help. I am trying to avoid running separate queries and concat them.

Share Improve this question edited Jan 20 at 13:48 Erwin Brandstetter 656k157 gold badges1.1k silver badges1.3k bronze badges asked Jan 20 at 12:50 nj167252nj167252 1733 silver badges15 bronze badges 0
Add a comment  | 

6 Answers 6

Reset to default 2
SELECT "order", status, eta
FROM   tbl
ORDER  BY status = 'complete'
     , EXTRACT(epoch FROM eta) * CASE WHEN status = 'complete' THEN -1 ELSE 1 END;

fiddle

The status = 'complete' evaluates to boolean, where false sorts before true.
If the column is defined NOT NULL, you are all set.
If the column isn't defined NOT NULL, use status IS NOT DISTINCT FROM 'complete' instead to make sure only 'completed' is sorted last.

  • Sorting null values after all others, except special
  • Sort NULL values to the end of a table

ASC and DESC are syntax elements and cannot be parameterized. For data types that can be "inverted", like numeric types, you can work around this limitation by multplying with -1 for descending order. So I convert the date with EXTRACT() and then conditionally multiply with -1. Here, a simple WHEN status = 'complete' covers null values, the first CASE branch is only entered on true.

Or an optimized variant of what you found yourself:

SELECT "order", status, eta
FROM   tbl
ORDER  BY status = 'complete'
     , CASE WHEN status = 'complete' THEN null ELSE eta END
     , CASE WHEN status = 'complete' THEN eta END DESC;

fiddle

All nice trickery. But it won't use plain indexes. This is more verbose, but less confusing and typically faster with an index on (status, eta):

(  -- parentheses required
SELECT "order", status, eta
FROM   tbl
WHERE  status <> 'complete'
ORDER  BY eta
)
UNION ALL 
(
SELECT "order", status, eta
FROM   tbl
WHERE  status = 'complete'
ORDER  BY eta DESC
);

fiddle

See:

  • Switch ASC / DESC in ORDER BY with a CASE construct?
  • Special variable FOUND not set properly?

And avoid reserved words like "order" as identifiers.

I would agree with previous comment where you should provide Data Sample and what you have tried.

Having said that, you can try the following query:

SELECT *
FROM orders
ORDER BY 
    CASE 
        WHEN status = 'pending' THEN 1
        WHEN status = 'complete' THEN 2
    END,
    CASE 
        WHEN status = 'pending' THEN eta
        WHEN status = 'complete' THEN eta END DESC;

Find the example here

Something like this will work in sql - you haven't told us what the tables are called

select order, status, eta
from myTable
order by status desc, eta asc
FROM dataorder
ORDER BY 
    CASE 
        WHEN status = 'complete' THEN 2
        ELSE 1
    END,
    CASE 
        WHEN status = 'pending' THEN eta
        WHEN status = 'complete' THEN eta
        ELSE eta
    END;

An option, if available, is creating a ENUM for the status column. Then declare the column as the enum type defined. Sorting on the status column is then determined by the sequence of defined values in the enum definition. (see demo).

create type order_status as enum
       ( 'pending'
       , 'sailing'
       , 'ordered'
       , 'complete'
       ); 
      
create table orders( ord_id  integer generated always as identity
                   , status  order_status
                   , eta     date
                   ); 

i assume that the model you use Order::Class, and order status like this [pending,sailing,ordered,complete]

maybe you can try this

Order::orderBy('eta', 'asc')
->orderBy('status', 'desc')

you should add a description for the status order it should be in

发布评论

评论列表(0)

  1. 暂无评论