SQL
WHERE IN clause
row sorting
database query
SQL tips

Sort the rows according to the order specified in WHERE IN clause

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

WHERE IN filters rows, but it does not preserve the input list order. If your UI or API expects results in the same sequence as requested identifiers, you need a custom sort expression. This article shows database-friendly ways to impose that order safely.

Why IN Does Not Guarantee Order

SQL result order is undefined unless you use ORDER BY. Even if rows seem to come back in list order during testing, that behavior is incidental and may change with execution plans or index updates.

Suppose you request products in the order 9, 2, 5. A plain query:

sql
SELECT id, name
FROM products
WHERE id IN (9, 2, 5);

returns the right rows but not necessarily in the requested sequence.

Portable Approach with CASE

A portable method is assigning rank values with CASE and sorting by that rank.

sql
1SELECT id, name
2FROM products
3WHERE id IN (9, 2, 5)
4ORDER BY CASE id
5    WHEN 9 THEN 1
6    WHEN 2 THEN 2
7    WHEN 5 THEN 3
8    ELSE 999
9END;

This works across major SQL systems and is easy to understand in code review.

For longer lists, generate the CASE expression in application code rather than writing it manually.

Database-Specific Shortcuts

Some databases provide helper functions for list-position ordering.

MySQL example:

sql
1SELECT id, name
2FROM products
3WHERE id IN (9, 2, 5)
4ORDER BY FIELD(id, 9, 2, 5);

PostgreSQL example with array position:

sql
1SELECT id, name
2FROM products
3WHERE id = ANY (ARRAY[9, 2, 5])
4ORDER BY array_position(ARRAY[9, 2, 5], id);

These are concise and readable, but they reduce portability.

Scalable Pattern with a Derived Order Table

For dynamic or long lists, build a small derived table that stores requested order and join on it.

sql
1WITH requested(id, ord) AS (
2    VALUES
3        (9, 1),
4        (2, 2),
5        (5, 3)
6)
7SELECT p.id, p.name
8FROM products p
9JOIN requested r ON p.id = r.id
10ORDER BY r.ord;

This pattern scales well and can be reused for pagination or additional joins. It is often cleaner than very long CASE blocks.

Application-Layer Query Construction

If input IDs come from an API call, parameterize safely and avoid string concatenation of raw values. Build the order table or CASE expression from validated identifiers only.

In back-end services, enforce a maximum list size. Very large IN lists can degrade planning and execution. For heavy workloads, upload IDs to a temporary table and join instead.

Keeping Query Plans Efficient

Custom ordering expressions can affect optimizer choices, especially on large tables. Keep filtering predicates selective and ensure join keys remain indexed before adding ranking logic. If request lists are large, temporary tables with indexed keys usually perform better than giant literal lists.

Collect execution plans for representative query sizes and track latency over time. This helps detect when a custom ordering pattern that worked in development becomes a bottleneck in production workloads.

Common Pitfalls

A common mistake is assuming ORDER BY id will match request order. It only sorts numerically or lexicographically, not by caller sequence.

Another issue is duplicate identifiers in the request list. Decide policy early, either preserve first occurrence or deduplicate before query generation.

Teams also forget to handle missing rows. If one requested ID does not exist, the output order still needs to be deterministic for existing rows.

Finally, avoid unsafe SQL string building for custom ordering. Always parameterize values and validate input to prevent injection risk.

Summary

  • WHERE IN filters rows but does not preserve input sequence.
  • Use ORDER BY CASE for a portable custom order.
  • Use FIELD or array_position when database-specific shortcuts are acceptable.
  • For long dynamic lists, join against a derived order table.
  • Parameterize generated SQL and define duplicate-ID behavior explicitly.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design