按组排序不起作用 - Laravel

54

我无法在Laravel 5.3中运行这个简单的查询。

$top_performers = DB::table('pom_votes')
        ->groupBy('performer_id')
        ->get();

这给了我:

SQLSTATE[42000]: Syntax error or access violation: 1055 'assessment_system.pom_votes.id' isn't in GROUP BY (SQL: select * from `pom_votes` group by `performer_id`)

然而,如果我从错误中复制原始查询并直接在PhpMyAdmin中执行,它可以正常工作。
我已经检查过这个链接:https://laravel.com/docs/5.3/queries#ordering-grouping-limit-and-offset 如果可以得到帮助,将不胜感激。
谢谢,
Parth Vora

您的数据库中似乎有一些“错误”。从错误信息中可以看出,MySQL 期望存在字段 assessment_system.pom_voted.id,但实际上并不存在。 - Loek
更有用的教程: Laravel 8 分组查询不起作用-已修复 - Fefar Ravi
8个回答

194

编辑应用程序的数据库配置文件config/database.php

mysql数组中,将strict => false设置为禁用MySQL的严格模式。


5
你能详细说明为什么这会解决问题吗? - Ken
@Md.JewelMia 为什么这个能工作?strict 是做什么的,将其改为 false 会有什么副作用? - Jacob
16
禁用严格模式不是一个好的解决方案。请看@GabrieleCiech的下面的答案。 - Amin.Qarabaqi
我们如何在Laravel中设置Oracle连接? - Vikas Chauhan
如果我运行PostgreSQL会怎样? - user151496
不要忘记运行 php artisan config:cache - NightOwl

59

也许您的问题是由于使用了MySQL服务器版本5.7.5+。从这个版本开始,GROUP BY的工作方式已经改变,因为他们使其行为符合SQL99(在以前的版本中它不是这样)。

尝试进行完整分组或更改您的MySQL服务器配置。

链接到官方MySQL文档,其中完整的GROUP BY被解释说明。


8

与其禁用严格模式('strict' => false),更安全的方法是通过向配置传递一个数组,仅启用所需模式:

// config/database.php
    
    'connections' => [
        //...
        'mysql' => [
            //...
            'strict'      => true,
            'modes'       => [
                //'ONLY_FULL_GROUP_BY', // Disable this to allow grouping by one column
                'STRICT_TRANS_TABLES',
                'NO_ZERO_IN_DATE',
                'NO_ZERO_DATE',
                'ERROR_FOR_DIVISION_BY_ZERO',
                //'NO_AUTO_CREATE_USER', // This has been deprecated and will throw an error in mysql v8
                'NO_ENGINE_SUBSTITUTION',
            ],
        ],
    ],

如果您在更改设置后仍然遇到相同的错误,请尝试通过运行php artisan config:cache来清除配置缓存。


4

有一些方法可以解决这个问题

#1

只获取我们正在分组的列,本例中为category_id。

注意:select中的列必须存在于groupBy中,反之亦然。

$posts = Post::query()
    ->select('category_id')
    ->groupBy('category_id')
    ->get();
类别ID
1
2

#2

但我想要所有列!

好的,你想要获取所有列。那么诀窍是不要在数据库级别上使用 groupBy()。相反,你可以在返回的集合中使用它。

$posts = Post::query()
    ->get()
    ->groupBy('category_id');

[
 
'1' => [
    ['id' => 1, 'name' => 'Post 1', 'category_id' => 1, 'author_id' => 4 'visits' => 32],
    ['id' => 2, 'name' => 'Post 2', 'category_id' => 1, 'author_id' => 8 'visits' => 12],
],
'2' => [
    ['id' => 3, 'name' => 'Post 3', 'category_id' => 2, 'author_id' => 12 'visits' => 201],
    ['id' => 4, 'name' => 'Post 4', 'category_id' => 2, 'author_id' => 4 'visits' => 0],
],

]

#3

在Laravel中,可以通过将其设置为false来简单地禁用“严格模式”(strict mode),并在database.php配置文件中进行设置。虽然这是可能的,但我不建议这样做。最好花时间学习如何编写正确的SQL查询,因为关闭“严格模式”所得到的结果可能是不可预测的,并且会在以后导致问题。

参考资料

https://sinnbeck.dev/posts/laravel-groupby-error


3

打开 config/database.php 文件。

将 strict 的值改为 false。

return [
   'connections' => [
      'mysql' => [
         'strict' => false
       ]
   ]
]

2
您可以在查询之前定义此行,假设您想使用 groupBy,那么只需在使用 groupBy 的位置之前添加此行即可,而无需将配置 strict 更改为 false:
\DB::statement("SET SQL_MODE=''");//this is the trick use it just before your query where you have used group by. Note: make sure your query is correct.

//this is just an example code.

$Rspatients = DB::table('reports')
->select(
    DB::raw("day(created_at) as day"),
    DB::raw("Count(*) as total_patients"))

->orderBy("created_at")
->groupBy(DB::raw("day(created_at)"))
->get();

0

我的公司使用原始SQL来运行分组操作,而不会冒险更改MySQL设置。

这里有一个工作示例:

public static function getPositivesDaily($start_date, $end_date, $admin_id)
{
    $positives = DB::select(
        'select COUNT(inspections.id) as total,DATE_FORMAT(inspections.created_at, :format) as date
            from inspections
            where inspections.created_at between :start_date and :end_date
            and inspection_results = 1
            and admin_id = :admin_id
            GROUP BY date',
    ['format'=>'%Y-%m-%d', 'start_date'=>$start_date, 'end_date'=> $end_date, 'admin_id'=>$admin_id]
    );


    return $positives;
}

如果您对这段代码有任何疑问,请随时向我提问,我会尽快回复。 谢谢。

-6

如果您关闭了严格模式,则无法使用其他严格功能来修复此错误。请前往Illuminate\Database\Connectors\MySqlConnector.php并更改以下函数:

protected function strictMode() {
return "set session
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY
_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION'";
}

用这个替换函数。


永远不要编辑软件包的源代码。 - miken32

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接