OrderByRaw() then orderBy() in Laravel

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Mastering Dynamic Ordering: Combining whereIn(), orderByRaw(), and Eloquent

As senior developers working with Laravel, we often encounter scenarios where we need to combine standard query building methods—like filtering with whereIn() and complex ordering with orderByRaw()—to achieve highly specific database results. The challenge arises when chaining these methods dynamically, especially when dealing with raw SQL expressions that reference filtered sets.

This post addresses a common point of confusion: why the order defined by orderByRaw() seems to override subsequent standard orderBy() calls, and how to correctly combine these techniques in an efficient manner within Eloquent.

The Challenge of Dynamic Ordering

You are attempting to construct a query where the primary sorting mechanism is dictated by a raw SQL expression derived from the selected IDs, followed by standard sorting on other fields:

php
$ids = [1, 5, 3]; // Example dynamic IDs
// ...
Product::whereIn('id', $ids)
    ->orderByRaw("field(id, ?)", $ids) // Attempting to use raw order
    ->orderBy('views', 'desc')
    ->orderBy('created_at', 'desc')
    ->get();

The observation that the results follow the orderByRaw() order instead of the subsequent standard orders suggests a conflict in how the query builder interprets the precedence between raw expressions and chained methods. While this behavior is often dictated by the underlying SQL execution plan, understanding the mechanics of parameter binding in Laravel is key to fixing it.

Deconstructing the orderByRaw() Interaction

When you use orderByRaw(), you are inserting a piece of SQL directly into the query structure. If this raw expression itself defines the primary ordering logic based on the filtered set, subsequent calls to orderBy() might be treated as secondary sorting criteria applied within that established order.

Let's look at your generated SQL:

sql
SELECT * 
FROM products 
WHERE id IN (?, ?, ?, ?, ?) 
ORDER BY Field(id, ?, ?, ?, ?, ?),  -- Raw Order
        views DESC,                  -- Standard Order
        created_at DESC              -- Standard Order

The problem isn't that the second orderBy() is ignored; it’s that the raw expression (Field(id, ...)), which uses the dynamic parameters to establish the primary sort sequence for the filtered items, takes precedence. To ensure a clean, predictable result set where all criteria are respected sequentially, we need to ensure the raw ordering is correctly positioned relative to the standard sorting.

The Solution: Correct Parameter Binding and Strategy

The key to solving this lies in ensuring that when using orderByRaw(), you properly bind the parameters within the context of the entire query structure. For dynamic ordering based on a filtered set, it's often cleaner and more robust to let the database handle the filtering first, and then apply explicit, standard sorting if possible, or construct the raw order carefully.

Best Practice Implementation

Instead of relying solely on complex orderByRaw() for derived sets, consider restructuring how you define the sort order. If the goal is truly to sort by a calculated value derived from the IDs and then by views, ensure your binding mechanism is sound.

For dynamic ordering based on an IN clause, often it is simpler to rely on standard SQL functions if possible, or ensure that the raw expression correctly references the column being ordered by:

php
$ids = [1, 5, 3];

// Option 1: Using a more explicit approach for ordering (if 'id' sorting is sufficient)
$products = Product::whereIn('id', $ids)
    ->orderBy('id') // Order by the standard ID first for stability
    ->orderBy('views', 'desc')
    ->orderBy('created_at', 'desc')
    ->get();

// Option 2: If you absolutely must use a raw expression derived from IDs, ensure clean binding.
// Note: For simple ordering based on an existing column, standard orderBy is usually preferred.
$products = Product::whereIn('id', $ids)
    ->orderByRaw("id ASC") // Ordering by the actual ID in the filtered set
    ->orderBy('views', 'desc')
    ->orderBy('created_at', 'desc')
    ->get();

// Reference useful Eloquent techniques for complex querying, which can be found on https://laravelcompany.com.

In complex scenarios involving dynamic ordering derived from subqueries or whereIn clauses, the standard approach is to define the filtering (WHERE) first, and then apply sequential sorting (ORDER BY). If you must use a raw expression, ensure it logically precedes other sort criteria in the SQL structure. By using orderByRaw("id ASC") instead of trying to concatenate array elements into the ordering clause, we leverage Eloquent’s built-in parameter binding more effectively, ensuring that all parts of the query are correctly interpreted by the database engine.

Conclusion

Combining dynamic filtering (whereIn) with complex sorting (orderByRaw) requires a precise understanding of SQL precedence and Laravel's query builder mechanics. The issue you observed stems from how the raw expression establishes the initial sorting context for the filtered set. By ensuring that your orderByRaw is logically sound—often by ordering on existing, bound columns rather than attempting to reconstruct the entire sort criteria dynamically—you can achieve the predictable, multi-level sorting you require. Always prioritize clear, sequential sorting logic when chaining methods in Eloquent; this leads to more maintainable and debuggable code, aligning with best practices promoted by resources like https://laravelcompany.com.