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

如何用Laravel查询构建器计算一对多关系下的平均等待时间

解决Laravel中计算就诊到首次生命体征检查平均等待时间的问题

核心逻辑是:先为每个就诊记录匹配其对应的最早生命体征检查记录,计算两者的时间差,最后求这些时间差的平均值,而非所有生命体征记录与就诊记录的平均。

正确的Laravel查询构建器实现

// 计算所有有生命体征记录的就诊的平均等待时间(单位:分钟)
$averageWaitTime = DB::table('visits')
    ->joinSub(
        // 子查询:按就诊ID分组,获取每个就诊的首次生命体征检查时间
        DB::table('vital_signs')
            ->select('visit_id', DB::raw('MIN(created_at) as first_vital_at'))
            ->groupBy('visit_id'),
        'first_vitals',
        'visits.id',
        '=',
        'first_vitals.visit_id'
    )
    ->select(DB::raw('AVG(TIMESTAMPDIFF(MINUTE, visits.created_at, first_vitals.first_vital_at)) as average_wait_minutes'))
    ->value('average_wait_minutes');

错误原因分析

  1. 错误计算所有记录平均值:直接关联visits和vital_signs全表会导致每个就诊对应多条生命体征记录,计算的是所有时间差的平均,而非首次检查的平均。
  2. 1111分组函数误用错误:如果直接在主查询中使用MIN(vital_signs.created_at)但未按visit_id分组,或者将聚合函数与非聚合字段混用且未正确分组,就会触发该错误——MySQL要求聚合函数必须配合对应的分组逻辑。
  3. havingRaw返回空集合:HAVING子句是对分组后的结果进行过滤,若你的havingRaw条件未匹配到分组后的有效数据(比如条件逻辑错误、没有符合条件的分组),就会返回空集合。

扩展:处理无生命体征记录的就诊

如果需要排除没有生命体征记录的就诊,可使用leftJoinSub并添加过滤条件:

$averageWaitTime = DB::table('visits')
    ->leftJoinSub(
        DB::table('vital_signs')
            ->select('visit_id', DB::raw('MIN(created_at) as first_vital_at'))
            ->groupBy('visit_id'),
        'first_vitals',
        'visits.id',
        '=',
        'first_vitals.visit_id'
    )
    // 过滤掉没有生命体征记录的就诊
    ->whereNotNull('first_vitals.first_vital_at')
    ->select(DB::raw('AVG(TIMESTAMPDIFF(MINUTE, visits.created_at, first_vitals.first_vital_at)) as average_wait_minutes'))
    ->value('average_wait_minutes');

时间单位调整

若需要其他时间单位(如秒、小时),只需修改TIMESTAMPDIFF的第一个参数,比如TIMESTAMPDIFF(SECOND, ...)或TIMESTAMPDIFF(HOUR, ...)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 09:22:46