You need to enable JavaScript to run this app. Laravel 8使用Eloquent按年龄差跨两表查询并按分类分组
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 8使用Eloquent按年龄差跨两表查询并按分类分组

Laravel 8 场景下的分类匹配查询实现方案

核心规则校准

首先明确和常规年龄计算的差异:本次年龄计算的基准点是当前自然年的12月31日,不是当前实时日期,计算的是从人员出生日期到该基准点的完整整年间隔,不能用简单的年份差值计算,避免把未到生日的年龄算大。

分步实现逻辑

  • 用SQL原生表达式封装固定计算逻辑,避免把数据拉到PHP层循环计算,大幅提升查询效率
  • 采用范围关联的方式匹配对应分类,无需固定外键依赖
  • 带上peoples表的有效数据筛选条件(is_visible=1)
  • 最终按分类名称完成结果分组

参考代码

常规数据量场景(PHP集合层分组)

适合人员数据量在万级以内的场景,逻辑灵活,后续如果需要对人员字段做格式化处理更方便:

use Illuminate\Support\Facades\DB;

// 生成当年最后一天的日期表达式
$yearEnd = DB::raw("DATE_FORMAT(NOW(), '%Y-12-31')");
// 计算人员符合规则的年龄值
$ageCalc = DB::raw("TIMESTAMPDIFF(YEAR, peoples.date_of_birth, {$yearEnd})");

$groupedData = DB::table('peoples')
    // 左连接关联符合年龄范围的分类,未匹配到分类的人员会保留
    ->leftJoin('categories', function ($join) use ($ageCalc) {
        $join->where($ageCalc, '>=', DB::raw('categories.min_age'))
             ->where($ageCalc, '<=', DB::raw('categories.max_age'));
    })
    // 过滤仅可见的人员数据
    ->where('peoples.is_visible', 1)
    ->select(
        'peoples.id',
        'peoples.name',
        'peoples.date_of_birth',
        // 未匹配到分类的统一标记为未分类
        DB::raw("IFNULL(categories.name, '未分类') as category_name")
    )
    ->get()
    // 按分类名称完成分组
    ->groupBy('category_name');

大数据量场景(SQL层分组)

适合人员数据量超过十万级的场景,直接在数据库层面完成分组聚合,减少PHP侧的内存占用:

// 复用上面定义的$yearEnd、$ageCalc表达式
$groupedData = DB::table('peoples')
    ->leftJoin('categories', function ($join) use ($ageCalc) {
        $join->where($ageCalc, '>=', DB::raw('categories.min_age'))
             ->where($ageCalc, '<=', DB::raw('categories.max_age'));
    })
    ->where('peoples.is_visible', 1)
    ->select(
        DB::raw("IFNULL(categories.name, '未分类') as category_name"),
        // 直接聚合每个分类下的人员列表为JSON格式
        DB::raw("JSON_ARRAYAGG(JSON_OBJECT('people_id', peoples.id, 'people_name', peoples.name)) as people_list")
    )
    ->groupBy('category_name')
    ->get();

避坑提示

  • 年龄计算别用年份直接相减:如果写YEAR(今年最后一天) - YEAR(出生日期),遇到生日在当前时间点之后的(也就是现在还没过当年生日的),年龄会比实际到当年最后一天的间隔多算1岁,和规则要求不符
  • 连接方式按需调整:如果业务不需要保留没匹配上分类的人员,把leftJoin换成innerJoin就行
  • 提前排查分类区间:如果categories表的min_age、max_age存在区间重叠,会导致同一个人匹配到多个分类、出现重复数据,上线前最好加约束保证区间连续不重叠

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.02 10:54:04