Laravel groupBy with pagination
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
# Mastering Grouping and Pagination in Laravel: Solving the `ONLY_FULL_GROUP_BY` Dilemma
As developers working with relational databases through frameworks like Laravel, we often encounter situations where the elegant simplicity of Eloquent or the Query Builder clashes with the strict rules imposed by the underlying SQL engine. A very common scenario arises when attempting to combine grouping operations (`groupBy()`) with result set retrieval and pagination (`paginate()`).
Today, we’re diving into a specific pain point: trying to group data from a table and paginate the results using the Query Builder, which frequently leads to the infamous `SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of SELECT list is not in GROUP BY clause...` error.
This post will explain why this happens and provide the robust, developer-approved solutions for achieving grouped pagination in Laravel applications.
---
## The Anatomy of the Error: Understanding `ONLY_FULL_GROUP_BY`
The error you are encountering stems directly from the strict SQL mode applied by many modern database systems (like MySQL with `sql_mode=only_full_group_by`).
When you use `GROUP BY serie`, you are instructing the database to collapse multiple rows into a single summary row based on that grouping field. The rule dictates that any column included in your `SELECT` list *must* either be part of the `GROUP BY` clause or be wrapped in an aggregate function (like `COUNT()`, `SUM()`, `MAX()`).
Your original attempt:
```php
InvoiceModel::selectRaw('*')
->groupBy('serie')
->paginate(15);
```
When you use `selectRaw('*')` alongside `groupBy('serie')`, the database sees that it needs to return information for every column in the table, but it can only definitively know the value of one non-grouped column (the actual detail row), causing the conflict.
## Solution 1: Aggregation First (The Database-Centric Approach)
If your goal is truly to *group* and get a summary, you must explicitly tell the database what you want to aggregate. Instead of selecting `*`, select the grouping field and the aggregated results.
Let's assume you want to group by `serie` and count how many invoices exist for each series:
```php
$groupedData = InvoiceModel::select('serie', \DB::raw('count(*) as invoice_count'))
->groupBy('serie')
->orderBy('serie')
->paginate(15);
// $groupedData will now contain only 'serie' and the calculated count for each group.
```
This approach is highly efficient because the heavy lifting (grouping and counting) is performed by the database engine, which is optimized for these operations. This aligns perfectly with best practices when leveraging Eloquent and the Query Builder, as promoted by resources like those found on [laravelcompany.com](https://laravelcompany.com).
## Solution 2: Post-Processing with Eloquent Collections (The Application Layer Approach)
If your requirement is not a true SQL grouping but rather displaying related data grouped in PHP—perhaps you want to group invoices by `serie` and then use the resulting groups for pagination—a cleaner, more flexible approach is to pull all the required data first and perform the grouping in your application layer. This avoids complex, potentially slow, database groupings when the final presentation logic is complex.
```php
$invoices = InvoiceModel::with('someRelation')->get();
// Group the results in PHP
$groupedResults = $invoices->groupBy('serie');
// Now you can paginate the resulting collection (though pagination on grouped data requires careful design)
$paginatedGroups = $groupedResults->values()->paginate(15);
```
While this method is less performant for massive datasets compared to pure SQL aggregation, it offers superior control over the grouping logic and is often easier to debug when dealing with complex relationships. For simple counts or summaries, however, **Solution 1 (Database Aggregation)** remains the most idiomatic and high-performance choice.
## Conclusion: Choosing the Right Tool
When faced with the `ONLY_FULL_GROUP_BY` error in Laravel, the key is to stop trying to force a full row selection (`SELECT *`) into a grouping operation.
1. **For Summaries (Counts, Sums):** Always use explicit aggregate functions (`COUNT()`, `SUM()`) combined with `GROUP BY`. This delegates the work efficiently to your database.
2. **For Complex Grouping/Presentation:** If the requirement is complex or involves relationships that don't map cleanly to simple aggregates, consider fetching the data first and handling the grouping within Eloquent Collections in your application layer.
By understanding the constraints of SQL modes, you can write more robust and predictable database queries, ensuring your Laravel applications remain fast, clean, and reliable, much like the principles taught by [laravelcompany.com](https://laravelcompany.com).