【问题标题】:Laravel DB select generates unexpected SQL error after some data bindingsLaravel DB select 在某些数据绑定后生成意外的 SQL 错误
【发布时间】:2018-07-17 08:27:31
【问题描述】:

以下 SQL 在 phpmyadmin 控制台中运行良好:

SELECT  count(tca.cavity_id),GROUP_CONCAT(DISTINCT(tca.cavity_id)),equipments.eqtype_id, eqtypes.title FROM cavity_actions AS tca

  LEFT JOIN equipments ON tca.equipment_id = equipments.id
  LEFT JOIN eqtypes ON equipments.eqtype_id = eqtypes.id
WHERE tca.job_id = 6 AND tca.action_id = 2
AND tca.created_at BETWEEN '2018-01-31 00:00:00' AND '2018-02-01 00:00:00'
AND equipments.eqtype_id = 2 

这是来自 phpmyadmin 的屏幕截图,显示了正在运行的查询:

但是,当我尝试将 DB::select() 与如下数据绑定一起使用时:

$sql = 'SELECT  count(tca.cavity_id),GROUP_CONCAT(DISTINCT(tca.cavity_id)),equipments.eqtype_id, eqtypes.title FROM cavity_actions AS tca

  LEFT JOIN equipments ON tca.equipment_id = equipments.id
  LEFT JOIN eqtypes ON equipments.eqtype_id = eqtypes.id
WHERE tca.job_id = :jobId AND tca.action_id = 2
AND tca.created_at BETWEEN :start AND :end
AND equipments.eqtype_id = :eqtypeId';
    foreach ($eqtypes as $eqtype){
        DB::enableQueryLog();
        $data = [ 'jobId' => $job->id, 'eqtypeId' => 1,  'start' => $start, 'end' => $end];
        $out[$eqtype->id] = DB::select($sql,$data);
       // dd(DB::getQueryLog());

        return $out;
    }

它会产生纯 SQL 错误:

SQLSTATE[42000]:语法错误或访问冲突:1140 在聚合中 没有 GROUP BY 的查询,SELECT 列表的表达式 #3 包含 非聚合列“factory2.equipments.eqtype_id”;这是 与 sql_mode=only_full_group_by 不兼容(SQL:SELECT 计数(tca.cavity_id),GROUP_CONCAT(DISTINCT(tca.cavity_id)),equipments.eqtype_id, eqtypes.title FROMcavity_actions AS tca

在 tca.equipment_id = equipments.id 上左连接设备 eqtypes ON devices.eqtype_id = eqtypes.id WHERE tca.job_id = :jobId AND tca.action_id = 2 AND tca.created_at BETWEEN :start AND :end AND 设备.eqtype_id = :eqtypeId)

尝试调试问题,我尝试在查询中为每个数据绑定提供固定值,通过这种方式它可以工作。

当我移除 :eqtypeId 时,它还特别适用:

AND tca.created_at BETWEEN :start AND :end
AND equipments.eqtype_id = 1';
    foreach ($eqtypes as $eqtype){
        DB::enableQueryLog();
        $data = [ 'jobId' => $job->id,  'start' => $start, 'end' => $end];
        $out[$eqtype->id] = DB::select($sql,$data);
       // dd(DB::getQueryLog());

但只是使用 :eqtypeId 并将其提供给数据绑定,它会再次生成该 SQL 错误!

我的意思一切正常,直到我在 laravel 应用程序中为最后一个 where 子句条件 AND equipments.eqtype_id = :eqtypeId 使用数据绑定。

让我的代码在 laravel 中工作的唯一方法是将 ...AND equipments.eqtype_id = :eqtypeId 替换为 AND equipments.eqtype_id = %s 然后使用 sprintf 就像:$out[$eqtype->id] = DB::select(sprintf($sql,$eqtype->id),$data);

我需要一个解释,为什么它不适用于仅用于最后一个 where 条件的普通数据绑定!数据绑定对查询有什么不同?

phpmyadmin 和 laravel 应用程序都使用相同的 MySQL 服务器和相同的 Apache 服务器上的相同 PHP 版本!

【问题讨论】:

  • 您的查询毫无意义,因为您选择了聚合(即COUNTGROUP_CONCAT)以及非聚合的单个列。更新您的问题并告诉我们您要在此处选择什么。请注意,在大多数数据库中,您的查询到处都会失败。
  • @TimBiegeleisen 我刚刚用屏幕截图编辑了这个问题,显示它通过 phpmyadmin 工作。
  • 我的话被置若罔闻。您的查询无效,它不应在任何地方运行,您需要修复它。您不能同时选择聚合列和非聚合列,这是没有意义的。
  • 难道旧的 mysql 版本不允许这样做吗?我以为直到最近他们才开始强制执行聚合/非聚合不匹配?还是我完全不在基地?
  • @btl 使用的 MySQL 服务器是 5.7.21 版本

标签: php mysql laravel-5 phpmyadmin


【解决方案1】:

这是strict mode 开启的结果。 Laravel 在config/database.php 中有一个严格模式的设置。

使用严格模式通常是个好主意,因为它会在您做一些模棱两可的事情时告诉您。但如果您不想打开,可以更改设置。

    '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' => 'utf8mb4',
        'collation' => 'utf8mb4_unicode_ci',
        'prefix' => '',

        // Changes MySQL strict mode settings
        'strict' => false,

        'engine' => null,
    ],

【讨论】:

  • 请注意,它是具有相同 MySQL 配置的相同查询,唯一的区别在于它是否有效只是使用绑定。换句话说,当不使用绑定数据之一时,查询在 laravel 中运行良好。即直接在查询中替换它。
猜你喜欢
  • 2018-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-03
  • 2018-02-14
  • 2014-12-02
  • 2020-11-17
  • 1970-01-01
相关资源
最近更新 更多