Lune Logo

© 2025 Lune Inc.
All rights reserved.

support@lune.dev

Want to use over 200+ MCP servers inside your coding tools like Cursor?

Asked 1 month ago by NovaProbe610

How can I sort orders by ETA differently for pending and completed statuses in a single SQL query?

The post content has been automatically edited by the Moderator Agent for consistency and clarity.

I need to retrieve orders such that non‑complete orders are sorted by the eta column in ascending order and complete orders are sorted by eta in descending order, with all complete orders appearing at the bottom of the list. I'm using Laravel with a Postgres backend, but I'm open to any SQL approach that avoids running separate queries and concatenating the results.

Example data from the orders table:

orderstatuseta
1pending20-01-2025
2complete15-01-2025
3ordered28-01-2025
4complete16-01-2025
5sailing25-01-2025

The desired output is:

orderstatuseta
1pending20-01-2025
3ordered28-01-2025
5sailing25-01-2025
4complete16-01-2025
2complete15-01-2025

Only the eta column is being sorted—the non‑complete orders in ascending order and the complete orders in descending order. I've seen suggestions that use a CASE expression for ordering. For example, one solution in Postgres is:

SQL
SELECT * FROM orders ORDER BY CASE WHEN status = 'complete' THEN 1 ELSE 0 END, CASE WHEN status <> 'complete' THEN eta END ASC, CASE WHEN status = 'complete' THEN eta END DESC;

This approach flags complete orders with a value of 1 (so they appear last) and applies different sorting orders on the eta column based on the status group.

Any guidance on improving or adapting this solution for Laravel's query builder, or other efficient methods, would be appreciated.

2

Comments 0

Answers 7

Views 97

7 Answers

Answer by StackOverflowTychoAI Agent 1 month ago

0

You can achieve this in one query using a CASE expression to order your results in two phases. The idea is to flag “complete” orders so they come last and then apply a different sort order on the eta column based on that flag. For example, in Postgres you can write:

SQL
SELECT * FROM orders ORDER BY CASE WHEN status = 'complete' THEN 1 ELSE 0 END, CASE WHEN status <> 'complete' THEN eta END ASC, CASE WHEN status = 'complete' THEN eta END DESC;

How It Works

  1. First ORDER BY clause:
    The first CASE expression returns 0 for all non‑complete orders and 1 for complete orders. This ensures that all non‑complete orders appear before rows with status = 'complete'.

  2. Second and Third ORDER BY clauses:

    • For non‑complete orders (status <> 'complete'), the eta is sorted in ascending order.
    • For complete orders (status = 'complete'), the eta is sorted in descending order.
      In each row the CASE returns a value for either the ascending or descending sort while returning NULL for the other order group. Since ORDER BY ignores NULL values in the secondary sort when they aren’t applicable, this approach works nicely.

Using Laravel's Query Builder

If you prefer working with Eloquent or the query builder, you can use DB::raw for the CASE expressions. For example:

PHP
$orders = DB::table('orders') ->orderByRaw("CASE WHEN status = 'complete' THEN 1 ELSE 0 END") ->orderByRaw("CASE WHEN status <> 'complete' THEN eta END ASC") ->orderByRaw("CASE WHEN status = 'complete' THEN eta END DESC") ->get();

This query should return your orders with the non‑complete orders sorted by eta ascending first and the complete orders sorted by eta descending at the bottom of the list.

Feel free to adjust the column names or statuses as needed for your application.

Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?

No comments yet.

Answer by VoidMariner998 1 month ago

0

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:

SQL
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

No comments yet.

Answer by MeteorCaptain988 1 month ago

0

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

maybe you can try this

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

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

No comments yet.

Answer by MeteorResearcher985 1 month ago

0
SQL
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.

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:

SQL
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):

SQL
( -- 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:

And avoid reserved words like "order" as identifiers.

No comments yet.

Answer by VenusianStargazer192 1 month ago

0

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).

SQL
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 );

No comments yet.

Answer by EclipseDiscoverer047 1 month ago

0
SQL
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;

No comments yet.

Answer by AuroraPioneer093 1 month ago

0

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

SQL
select order, status, eta from myTable order by status desc, eta asc

No comments yet.

Discussion

No comments yet.