How7o
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Reading: How to Count Records Grouped By a Column in Laravel Eloquent
Share
How7oHow7o
Font ResizerAa
  • OS
Search
  • Home
  • Tools
  • Prank Screens
  • Learn
  • Blog
  • Contact
Follow US
© 2024–2026 How7o. All rights reserved.
How7o > Free Laravel, PHP, WordPress & Server Tutorials > Web Development > How to Count Records Grouped By a Column in Laravel Eloquent
Web Development

How to Count Records Grouped By a Column in Laravel Eloquent

how7o
By how7o
Last updated: April 20, 2026
7 Min Read
Laravel Eloquent group by count — Book::groupBy('author') query with bar-chart aggregate icon
SHARE

Grouping records by a column and counting each group is a classic report query — “how many books per author”, “how many orders per status”, “how many users per country”. In Laravel the fluent builder makes laravel eloquent group by count a short chain: groupBy() plus a raw count(*) in the select list. This guide shows the exact pattern, the ONLY_FULL_GROUP_BY strict-mode pitfall that trips a lot of people up, and how to filter groups with havingRaw().

Contents
  • TL;DR
  • Basic grouped-count query
  • The ONLY_FULL_GROUP_BY pitfall
    • Fix 1 — align SELECT and GROUP BY
    • Fix 2 — disable strict mode for this connection
  • Filtering groups with HAVING
  • Collection-based grouping (small tables only)
  • Frequently asked questions
  • Related guides
  • References

Last verified: 2026-04-21 on Laravel 11 with PHP 8.3 and MySQL 8.0. Originally published 2023-02-07, rewritten and updated 2026-04-21.

TL;DR

Combine select('col', DB::raw('count(*) as total')) with groupBy('col') to get one row per distinct value of col plus a total column. Every non-aggregate column in the SELECT list must also appear in the groupBy() list under MySQL’s default strict mode. Use havingRaw() to filter groups.

Basic grouped-count query

Here is the canonical “books per author” query. Select the grouping column, add a raw count(*) aggregate with a friendly alias, and call groupBy() on the same column:

$books = Book::groupBy('author')
    ->select('author', DB::raw('count(*) as total'))
    ->get();

foreach ($books as $book) {
    echo "Author " . $book->author . " - " . $book->total . " books";
}

Compiled SQL:

SELECT author, count(*) as total FROM books GROUP BY author

The loop has access to the two aliases — $book->author and $book->total — even though those aren’t real model attributes from the books table schema. The result is an Eloquent collection of “pseudo-models” that exist only for the duration of the query.

The ONLY_FULL_GROUP_BY pitfall

The single most common error on a fresh MySQL 5.7+ or 8.x install looks like this:

SQLSTATE[42000]: Syntax error or access violation: 1055
Expression #N of SELECT list is not in GROUP BY clause
and contains nonaggregated column ... which is not functionally dependent
on columns in GROUP BY clause; this is incompatible with
sql_mode=only_full_group_by

It fires when your SELECT list includes a non-aggregated column that isn’t in the GROUP BY list. Two fixes:

Fix 1 — align SELECT and GROUP BY

Preferred. Add every non-aggregate selected column to the groupBy() list, or wrap it in an aggregate if you want a representative value:

Book::select('author', 'language', DB::raw('count(*) as total'))
    ->groupBy('author', 'language')
    ->get();

// or wrap in MAX() when the column shouldn't be part of the grouping:
Book::select('author', DB::raw('MAX(published_at) as latest'), DB::raw('count(*) as total'))
    ->groupBy('author')
    ->get();

Fix 2 — disable strict mode for this connection

If aligning the lists isn’t practical (legacy queries, shared code), turn strict mode off in config/database.php for the MySQL connection:

'mysql' => [
    // ...
    'strict' => false,
],

That removes ONLY_FULL_GROUP_BY (and other strict-mode flags) from the session. Use it as an escape hatch, not a default — the strict mode exists because GROUP BY with unlisted columns returns non-deterministic values and masks real bugs.

laravel eloquent group by count — groupBy + count(*) + havingRaw filter flow

Filtering groups with HAVING

WHERE filters rows before grouping; HAVING filters groups after. To show only authors with more than one book:

$books = Book::select('author', DB::raw('count(*) as total'))
    ->groupBy('author')
    ->havingRaw('count(*) > ?', [1])
    ->get();

Because total is declared as an alias in the SELECT list, you can also use the fluent form against the alias:

->having('total', '>', 1)

Collection-based grouping (small tables only)

Laravel collections have their own groupBy() that works entirely in PHP:

$perAuthor = Book::all()->groupBy('author')->map->count();
// $perAuthor is a keyed collection: ['Tolkien' => 3, 'Orwell' => 2, ...]

The syntax is terse and useful for small, already-in-memory collections. Do not use it on large tables — Book::all() loads every row, then PHP does the grouping work. The query-builder version pushes everything to MySQL and scales.

Frequently asked questions

Why do I get “SQLSTATE[42000] … only_full_group_by” errors?

MySQL 5.7+ enables ONLY_FULL_GROUP_BY strict mode by default, which requires every non-aggregated column in the SELECT list to appear in the GROUP BY clause. Either add the missing columns to groupBy(), wrap them in an aggregate like MAX(), or set 'strict' => false in config/database.php to disable the mode for that connection.

How do I filter groups by their count (HAVING clause)?

Use havingRaw() for count-based conditions: Book::select('author', DB::raw('count(*) as total'))->groupBy('author')->havingRaw('count(*) > ?', [1])->get(). That returns only authors with more than one book. You can also use the fluent having('total', '>', 1) since total is a declared alias in the SELECT.

Should I use groupBy() on the query or on the collection?

Almost always on the query. Book::all()->groupBy('author')->map->count() works and reads nicely, but it loads every row into PHP first — fine for small tables, terrible once you’re past a few thousand rows. The query-builder form pushes the work to MySQL and returns just the aggregated rows.

Can I group by multiple columns?

Yes — pass multiple column names to groupBy(): Book::select('author', 'language', DB::raw('count(*) as total'))->groupBy('author', 'language')->get(). Every selected non-aggregate column must be in the groupBy list (strict mode), which is another reason the SELECT and GROUP BY drift tends to cause errors.

How do I access both grouped columns and the count in Blade?

The select aliases become properties on each result row. With select('author', DB::raw('count(*) as total')), the loop gives you $row->author and $row->total. If you’d rather work with an Eloquent model instance, skip the groupBy aggregate and use withCount('books') on the parent model instead.

Related guides

  • How to Install Laravel on Ubuntu — set up the framework before writing aggregate queries.
  • Best Way to Insert or Update Records in Laravel Eloquent — another single-query aggregate pattern.
  • How to Add Foreign Keys in Laravel Migration — relevant when grouping across a parent relationship.

References

Query-builder grouping, having, and raw expressions: laravel.com/docs/queries. Eloquent aggregates and withCount: laravel.com/docs/eloquent.

TAGGED:EloquentLaravelmysqlphpsqltroubleshooting

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
[mc4wp_form]
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Copy Link Print
Previous Article Laravel Eloquent count rows — Post::count query snippet with aggregate bar chart icon How to Count Rows in Laravel Eloquent Efficiently
Next Article Laravel Eloquent current month records — calendar and query builder illustration How to Get Current Month Records in Laravel Eloquent
Leave a Comment

Leave a Reply Cancel reply

You must be logged in to post a comment.

FacebookLike
XFollow
PinterestPin
InstagramFollow
Most Popular
Bun runtime — faster JS toolkit replacing npm in Laravel projects
How to Install Bun Runtime on Ubuntu (And Use It in a Laravel Project)
May 24, 2026
Tailscale mesh — peer-to-peer connections between devices, coordination server
How to Install Tailscale on Ubuntu (Zero-Config Mesh VPN for Self-Hosters)
May 24, 2026
Caddy server — automatic HTTPS, 3-line Caddyfile vs 25-line nginx config
How to Install Caddy Server on Ubuntu (Automatic HTTPS, Drop-in nginx Alternative)
May 24, 2026
Cloudflare Tunnel — outbound-only connection from server, no inbound port forward
How to Install Cloudflare Tunnel on Ubuntu (Expose Local Services, No Port Forwarding)
May 24, 2026
WireGuard encrypted tunnel between server and clients with lock icons
How to Set Up WireGuard VPN on Ubuntu (Server, Linux Client, and iOS)
May 24, 2026

You Might Also Like

Run Laravel queue workers with Supervisor
Web Development

How to Run Laravel Queue Workers in Production with Supervisor

12 Min Read
WooCommerce dynamic currency switcher — cookie-stored currency applied via woocommerce_currency filter
Web Development

How to Dynamically Change Currency in WooCommerce

7 Min Read
Check Bootstrap modal open or closed with jQuery
Web Development

How to Check if a Bootstrap Modal Is Open or Closed with jQuery

4 Min Read
Laravel unique validation that ignores the current record on update
Web Development

How to Validate a Unique Column on Update in Laravel

4 Min Read
How7o

We provide tips, tricks, and advice for improving websites and doing better search.

Tools

  • Age Calculator
  • Word Counter
  • Image Upscaler
  • Password Generator
  • QR Code Generator
  • See all tools→

Pranks

  • Fake Blue Screen Prank
  • Hacker Typer
  • Fake iMessage Generator
  • Windows XP Crash Prank
  • Windows 11 Update Prank
  • See all prank screens →

Company

  • About Us
  • Blog
  • Contact
  • Privacy Policy
  • Terms of Service
  • Sitemap
© 2024–2026 How7o. All rights reserved.
Welcome Back!

Sign in to your account

Username or Email Address
Password

Lost your password?