How can I solve inconsistent sql_mode = only_full_group_by in laravel eloquent?
My eloquent laravel looks like this:
$products = Product::where('status', 1)
->where('stock', '>', 0)
->where('category_id', '=', $category_id)
->groupBy('store_id')
->orderBy('updated_at', 'desc')
->take(4)
->get();
There is an error like this on execution:
SQLSTATE [42000]: Syntax error or access violation: 1055 Expression # 1 of the SELECT list is not in the GROUP BY clause and contains an unaggregated column 'myshop.products.id', which is functionally independent of the columns in the GROUP BY clause; this is incompatible with sql_mode = only_full_group_by (SQL: select * from
products
wherestatus
= 1 andstock
> 0 andcategory_id
= 5 groupstore_id
orderupdated_at
desc limit 4)
How can I solve it?
source to share
I had a similar problem and solved it by disabling mysql strict mode in the database connection settings.
'connections' => [
'mysql' => [
// Behave like MySQL 5.6
'strict' => false,
// Behave like MySQL 5.7
'strict' => true,
]
]
You can find even more config settings in this blog post by Matt Stauffer
source to share
In config => database.php folder make sure mysql strict is false like this
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8',
'collation' => 'utf8_general_ci',
'prefix' => '',
'strict' => false,
'engine' => null,
],
if true is set to true, set it to false, then clear config money by running this command in cmd
PHP Artisan Configuration: Clear
source to share
I solved this problem by adding the "mode" option and setting only those modes that I want to enable in config => database.php
'mysql' => [
...
'modes' => [
'STRICT_ALL_TABLES',
'ERROR_FOR_DIVISION_BY_ZERO',
'NO_ZERO_DATE',
'NO_ZERO_IN_DATE',
'NO_AUTO_CREATE_USER',
],
],
More in this tutorial
source to share
This is because recent MySQL versions behave like most dbms already in terms of offerings group by
; general rule
if you are using
group by
all the columns in theselect
need to be present ingroup by
or aggregate aggregation function (sum
,count
,avg
etc.),
Your current request is grouped with using store_id
, but since you select everything the above rule is not followed.
source to share
Check the request:
Product::where('status', 1)
->where('stock', '>', 0)
->where('category_id', '=', $category_id)
->groupBy('store_id')
->orderBy('updated_at', 'desc')
->take(4)
->get();
here you are grouping the data with store_id
and retrieving all columns in the result set that are not allowed. To fix this problem, select either store_id
the aggregation function on it or change the system variable sql_mode=only_full_group_by
to SET sql_mode = ''
.
source to share
To select only aggregated columns use one of the raw methods provided by Laravel . For example:
Product::selectRaw('store_id')
->where('status', 1)
->groupBy('store_id')
->get();
source to share
As stated, setting strict mode to false can lead to security bugs and I am trying to set sql_mode to empty before queries that require it. Please note that this is a TEMPORARY change, when your connection is closed (as requested by laravel), you will be assigned the sql_mode = only_full_group_by value (or higher).
DB :: statement ("SET sql_mode = ''");
Hooray, happy coding ...
PS: this is not a Laravel bug, if you try to execute this query directly on your DB you will encounter the same result. This workaround works in both mysql and the first statement, and again will be a temporary session change rather than a permanent one.
source to share
I solved it by setting the modes in config / database.php file.
Set the modes as follows:
'modes' => [
'STRICT_TRANS_TABLES',
'NO_ZERO_IN_DATE',
'NO_ZERO_DATE',
'ERROR_FOR_DIVISION_BY_ZERO',
'NO_ENGINE_SUBSTITUTION',
]
for MySQL driver
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
'modes' => [
'ONLY_FULL_GROUP_BY',
'STRICT_TRANS_TABLES',
'NO_ZERO_IN_DATE',
'NO_ZERO_DATE',
'ERROR_FOR_DIVISION_BY_ZERO',
'NO_ENGINE_SUBSTITUTION',
]
],
source to share