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

Laravel Eloquent使用FIND_IN_SET查询数组匹配逗号分隔字段方案

Laravel Eloquent 多值匹配逗号分隔字段查询及排序实现

问题根因

  • MySQL原生FIND_IN_SET()函数第一个参数仅支持传入单个字符串/数字值,直接传入数组会触发SQL语法错误,无法得到预期匹配结果
  • 该场景需要实现两个核心需求:匹配关联表size_ids字段包含传入size_id数组任意值的Offer记录;支持按传入的size数组规则对结果排序

可落地实现代码

所有参数使用PDO占位符绑定,避免SQL注入风险,代码兼容Laravel 6+所有版本:

// 预处理入参,过滤非法值,统一转成整型
$sizeIds = collect($input['size_id'])
    ->filter(fn($id) => is_numeric($id))
    ->map(fn($id) => (int)$id)
    ->values()
    ->toArray();

$offerQuery = Offer::whereHas('ApplyOn', function($query) use ($sizeIds) {
    // 多条件OR拼接FIND_IN_SET,命中任意一个size值即满足关联条件
    $query->where(function($subQuery) use ($sizeIds) {
        foreach ($sizeIds as $idx => $sizeId) {
            $sql = "FIND_IN_SET(?, size_ids)";
            $idx === 0 
                ? $subQuery->whereRaw($sql, [$sizeId])
                : $subQuery->orWhereRaw($sql, [$sizeId]);
        }
    });
});

// 追加排序逻辑:按传入size数组的顺序排序,匹配到数组中越靠前的值,记录排名越靠前
if (!empty($sizeIds)) {
    $placeholders = implode(',', array_fill(0, count($sizeIds), '?'));
    $offerQuery->join('apply_on', 'offers.id', '=', 'apply_on.offer_id')
        ->orderByRaw("FIELD(
            SUBSTRING_INDEX(SUBSTRING_INDEX(apply_on.size_ids, ',', FIND_IN_SET(?, apply_on.size_ids)), ',', -1),
            {$placeholders}
        ) ASC", array_merge([$sizeIds[0]], $sizeIds))
        ->select('offers.*')
        ->distinct();
}

$offer = $offerQuery->get();

可选排序规则调整

如果你需要按照「匹配到的size值数量越多、记录排名越靠前」的规则排序,把上述代码里的orderByRaw部分替换为如下代码即可:

$matchSql = collect($sizeIds)
    ->map(fn() => "IF(FIND_IN_SET(?, apply_on.size_ids), 1, 0)")
    ->implode('+');
$offerQuery->orderByRaw("({$matchSql}) DESC", $sizeIds);

注意事项

  • 代码里的关联表名apply_on、关联外键offer_id请和你实际的表结构、Eloquent关联配置保持一致
  • 用逗号分隔字段存储多值关联属于反范式设计,FIND_IN_SET类查询无法利用数据库索引,数据量较大时查询性能会明显下降,长期迭代建议新增多对多中间表存储关联关系,替代逗号拼接字段的存储方式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 14:15:53