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

Laravel Where查询中如何引用其他列值筛选进行中游戏回合

问题根因

原写法失效的核心问题是运算层级搞错了:

  • Carbon::now()->subMinutes()是PHP层面的逻辑,在SQL语句发送给数据库之前就已经执行完成,这时候还没读取rounds表中任意一行的duration字段值
  • 代码中裸写的duration属于PHP上下文的未定义常量,根本不会映射到数据库的duration字段,完全无法实现逐行动态计算

你需要把「开始时间+持续时长」的运算下推到SQL层执行,让数据库在遍历每一行回合记录时,用该行自己的duration值计算结束时间,再和当前时间比对。

可直接复用的实现代码

根据你使用的数据库类型,选对应的写法即可:

MySQL/MariaDB 环境(最常用)

直接用DATE_ADD函数做时间偏移计算,参数绑定防注入:

// 查询指定游戏下所有进行中的回合
$activeRounds = $game->rounds()
    ->whereRaw('DATE_ADD(start_time, INTERVAL duration MINUTE) > ?', [now()])
    ->get();

// 如果要查询存在进行中回合的游戏实例
$activeGame = Game::whereHas('rounds', function ($query) {
    $query->whereRaw('DATE_ADD(start_time, INTERVAL duration MINUTE) > ?', [now()]);
})->find($gameId);

PostgreSQL 环境

PostgreSQL的时间计算语法不同,用make_interval处理分钟偏移:

$activeRounds = $game->rounds()
    ->whereRaw("start_time + make_interval(mins => duration) > ?", [now()])
    ->get();

高版本Laravel优雅写法(Laravel 8+ 适配对应数据库后可用)

可以用DB::raw包裹字段运算表达式,不用写全量原生where:

$activeRounds = $game->rounds()
    ->where(now(), '<', DB::raw('DATE_ADD(start_time, INTERVAL duration MINUTE)'))
    ->get();
避坑提示
  • 不要尝试在PHP层提前计算固定时间阈值,每个回合的duration值独立,固定阈值无法适配所有回合记录
  • 所有传入SQL的动态值(比如当前时间)用参数绑定方式传入,不要直接拼接到SQL字符串中,避免SQL注入风险
  • 已经拿到$game实例的情况下,直接通过rounds()关联对象追加约束查询,比嵌套whereHas的写法性能更好。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:09:22