Laravel5 Eloquent关联查询:Items与Sells表匹配item_id获取商品标题
解决Laravel 5 Eloquent关联拼接分隔ID对应标题的问题
嘿,我来帮你搞定这个需求!首先先明确下咱们的数据源和目标:我们有两张非规范化设计的表,需要把Sells表中用空格分隔的item_id和Items表关联,最后拼接出对应的商品标题,得到类似“Sells表第1条记录的商品标题为A B”的结果。
先确认表结构
Items表
| id | item_id | item_title |
|---|---|---|
| 1 | 1002 | A |
| 2 | 1003 | B |
| 3 | 1004 | C |
Sells表
| id | item_id |
|---|---|
| 1 | 1002 1003 |
| 2 | 1003 1004 |
| 3 | 1004 1002 |
解决方案步骤
首先,咱们先定义好对应的Eloquent模型:
1. 创建模型
Items模型(app/Item.php)
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Item extends Model { protected $table = 'Items'; protected $primaryKey = 'id'; public $timestamps = false; // 如果表没有时间戳字段的话 }
Sells模型(app/Sell.php)
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Sell extends Model { protected $table = 'Sells'; protected $primaryKey = 'id'; public $timestamps = false; }
2. 编写关联查询逻辑
因为Sells表的item_id是空格分隔的字符串,没法直接用常规的关联,咱们需要用MySQL的字符串匹配结合分组拼接来实现。这里推荐用Laravel的查询构造器(也可以结合Eloquent)来写:
use App\Sell; use Illuminate\Support\Facades\DB; // 查询并拼接标题 $sellsWithTitles = Sell::select( 'Sells.id', DB::raw('GROUP_CONCAT(Items.item_title SEPARATOR " ") AS item_titles') ) ->join('Items', function ($join) { // 用CONCAT包裹避免部分ID匹配(比如1002和10021) $join->on(DB::raw('CONCAT(" ", Sells.item_id, " ")'), 'LIKE', DB::raw('CONCAT("% ", Items.item_id, " %")')); }) ->groupBy('Sells.id') ->get(); // 遍历输出结果 foreach ($sellsWithTitles as $sell) { echo "Sells表第{$sell->id}条记录的商品标题为{$sell->item_titles}\n"; }
3. 代码说明
- 关联条件:用
CONCAT(" ", Sells.item_id, " ")给Sells的item_id前后加上空格,再用LIKE匹配带前后空格的Items.item_id,这样可以避免出现类似1002被误匹配成10021的情况。 - GROUP_CONCAT:MySQL的聚合函数,用来把分组后的item_title用空格拼接成字符串,正好符合咱们的需求。
- 分组:按Sells的id分组,确保每条Sell记录对应一组拼接后的标题。
注意事项
⚠️ 这里要提醒下:这种把多个ID存在一个字段里的设计是非规范化的,会导致查询性能很差(没法利用索引),而且维护起来也麻烦。如果项目还在初期,强烈建议改成多对多关联:新建一个sell_item中间表,结构为id, sell_id, item_id,这样用Laravel自带的belongsToMany关联就能轻松实现需求,性能和可维护性都会好很多。
内容的提问来源于stack exchange,提问作者Mingeun Kim
相关产品推荐
相关产品推荐

