Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

dlook's avatar
Level 4

Laravel's groupBy() not working

So I'm trying to get a "top list" from my call log table it has "caller", "callee" and "duration" rows, what I want is to get like top 3 who made most calls in last 24 hours. I tried

CallLogModel::groupBy('caller')->get()

But groupBy is returning

SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 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

So I guess my question is - is there another way to get that "top X" list from eloquent model? Thanks.

0 likes
27 replies
lindstrom's avatar
Level 15

In MySQL 5.7, the sql mode ONLY_FULL_GROUP_BY is enabled by default, which means your select list must be in your aggregate functions (GROUP_BY, HAVING) assuming they are functionally dependent. See (seriously): https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

This will work:

CallLogModel::selectRaw('count(*) AS cnt, caller')->groupBy('caller')->orderBy('cnt', 'DESC')->limit(5)->get();

This will not:

CallLogModel::selectRaw('count(*) AS cnt, caller, callee')->groupBy('caller')->orderBy('cnt', 'DESC')->limit(5)->get();

If caller isn't functionally dependent on caller (and it wouldn't be), you can do this:

CallLogModel::selectRaw('count(*) AS cnt, caller, ANY_VALUE(callee)')->groupBy('caller')->orderBy('cnt', 'DESC')->limit(5)->get();

Or, again, disable ONLY_FULL_GROUP_BY. There is some other stuff out there if you want to read further about the pros/cons of leaving ONLY_FULL_GROUP_BY enabled. For most cases, it's probably fine to disable. Just keep it in the back of your mind as you write are verify your query results.

5 likes
dlook's avatar
Level 4

So here's what I did:

        $calls = Calls::select('call_id', DB::raw('COUNT(call_id) as count'))
            ->with('called')
            ->groupBy('call_id')
            ->orderBy('count', 'desc')
            ->get();

And this works, but it only obviously pulls in call_id and I can get data from called relationship, BUT I have another relationship called "info" and I need to pull info_id as well to get it with with('info')... So when I try to add that field to select it returns that same error from the original comment... Any thoughts @tomi ?

EDIT:

I just saw @lindstrom post and it freaking worked, I used ANY_VALUE(info_id) as info_id and got the relation "with('info')" working!!! Awesome answer!

lindstrom's avatar

@dlook Glad you sorted it out. Again, I'd just disable the default sql modes. Edit your my.cnf and add

sql_mode='' 

under [mysqld]. I just thought it would be worthwhile to explain what was going on in the event you couldn't change your config.

1 like
kamleshcgtechno's avatar

dear, it is already blank. I have checked in my phpmyadmin on the shared server. Any other suggestion? Please share. Thanks.

dlook's avatar
Level 4

@lindstrom Yeah, but I don't want to touch those settings on EBS... My manager always says "they're there for a reason". :)

lindstrom's avatar

@dlook The only way that response from your manager flies is if he's non-IT (in that case you're screwed). Otherwise it's a complete bullshit cop out. If he's being that dismissive, he sure as hell better be able to either a) enumerate the reasons from either knowledge/experience or research or b) pay someone to make these calls. He should know, for example, that if you migrated from 5.6 to 5.7, the only sql mode enabled by default was NO_ENGINE_SUBSTITUTION. Prior to 5.6.6, no modes were enabled. And from the fine manual for 5.7:

"The default SQL mode in MySQL 5.7 includes these modes: ONLY_FULL_GROUP_BY, STRICT_TRANS_TABLES, NO_ZERO_IN_DATE, NO_ZERO_DATE, ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER, and NO_ENGINE_SUBSTITUTION.

The ONLY_FULL_GROUP_BY and STRICT_TRANS_TABLES modes were added in MySQL 5.7.5. The NO_AUTO_CREATE_USER mode was added in MySQL 5.7.7. The ERROR_FOR_DIVISION_BY_ZERO, NO_ZERO_DATE, and NO_ZERO_IN_DATE modes were added in MySQL 5.7.8. For information about all available modes and default MySQL behavior, see Section 6.1.8, “Server SQL Modes”."

At any rate, I'm still happy you got it working.

3 likes
willvincent's avatar

My manager always says "they're there for a reason".

Sounds like manager speak for "I dunno wtf it's for, so I don't want you to touch it either." :D

5 likes
cent040's avatar

Go to your config/database.php folder. In mysql configuration array, change strict => true to strict => false, and everything will work nicely.

18 likes
COTIGA's avatar

IN

config/database.php

SET

'strict' => false,
26 likes
Adeguk's avatar

Thanks, @COTIGA, I had this same above issue with L9, and I surf through so many sites while the ans stirs me in the face

martinhschei's avatar

old issue i know, but this could help someone. :)

i got the same error and i just moved the groupBy to work on the collection returned from the query and not the query itself.

if you work with large datasets i would go for a groupBy in the database, but for something small groupBy on the collection should be fine.

EDIT: just realized you probably are trying to accomplish something else.

1 like
mehrancodes's avatar

In the case you don't want to change the database settings, run the query without groupBy, and then apply the groupBy on the result collection.

3 likes
hasnatbabur's avatar

Best explanation I found on internet ever! Thanks a lot!

Defcicer's avatar

Thanks a lot man, i was looking for this, and you just got me a solution that works for me <3

elybin's avatar

@cotiga this working perfectly! but, can you explain a little bit about the function? thanks

tazimul_lcast's avatar

@cotiga hi. I'm using 'sqlsrv'. Can you please tell me how to apply it in sqlsrv configuration? Thank you.

susheelbhai's avatar

I have resolved this issue by adding groupBy() after get()

example

CallLogModel::get()->groupBy('caller');

Tray2's avatar

@susheelbhai That is a bad solution, you are then doing the group by on the collection, and with php, instead of grouping in the database. This is a perfomance decrease, php is always slower than the database for these kinds of operations.

Please or to participate in this conversation.