You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel中如何为withCount添加having子句及解决相关报错

问题说明

需求为获取所有帖子数据,同时统计每个帖子下,经时区转换后(UTC转美国东部时间)创建时间早于等于2022-05-12 23:59:59的评论总数。
原有实现代码如下:

Route::get('/', function () {
  $base = Post::withCount([
    'comment' => function ($query) {
      $query->select(
        'id',
        'post_id',
        DB::raw('convert_tz(created_at, "UTC", "US/Eastern") as created_at_tz')
      )->having('created_at_tz', '<=', '2022-05-12 23:59:59')->count();
    },
  ]);

  return $base->get();
});

运行后抛出错误:

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'posts.id' in 'where clause'

select
  count(*) as aggregate
from
  (
    select
      convert_tz(created_at, "UTC", "US/Eastern") as created_at_tz
    from
      `comments`
    where
      `posts`.`id` = `comments`.`post_id`
    having
      `created_at_tz` <= 2022 -05 -12 23: 59: 59
  ) as `temp_table`
错误原因
  • withCount的闭包仅用于给统计查询添加约束条件,不能在闭包内手动调用count()这类执行方法。框架会自动构造关联统计的子查询、绑定帖子和评论的外键关联,手动调用count()会破坏子查询的上下文绑定,导致外层posts表的字段无法被子查询识别,触发找不到posts.id的错误。
  • 闭包内手动调用select()指定字段属于多余操作。withCount生成聚合查询时会自动选取需要的字段,手动指定select会覆盖框架默认的字段逻辑,进一步导致关联绑定异常。
  • 时间条件的写法存在两个问题:一是用having过滤聚合前的行效率低于where;二是时间值没有做参数绑定,最终生成的SQL里时间被解析成了算术减法表达式,就算解决了字段不存在的问题,统计结果也会完全错误。
正确实现

直接在闭包内通过whereRaw添加时区转换的过滤条件即可,不需要手动select、不需要手动调用count:

Route::get('/', function () {
    $posts = Post::withCount([
        // 注意如果你的模型关联定义的是复数comments,这里要改成'comments'
        'comment' => function ($query) {
            $query->whereRaw(
                'CONVERT_TZ(created_at, "UTC", "US/Eastern") <= ?',
                ['2022-05-12 23:59:59']
            );
        }
    ])->get();

    return $posts;
});

补充优化提示:如果你的数据库没有导入MySQL时区表,CONVERT_TZ函数会返回null导致统计失效。这种场景可以提前把目标时间换算成UTC时间再直接比较:2022年5月美国东部处于夏令时,比UTC晚4小时,2022-05-12 23:59:59美东时间对应的UTC时间是2022-05-13 03:59:59,直接用where('created_at', '<=', '2022-05-13 03:59:59')做比较即可,不需要调用数据库函数,查询性能更高。

内容的提问来源于stack exchange,提问作者Axel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 03:54:22