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

Laravel/SQL获取指定分类的所有父级及自身数据问题求助

问题:获取自关联分类表的所有父级(含自身)数据

我有一个categories表(实际表名为forum_categories),通过parent_id字段做自关联外键,想要获取指定分类的所有父级数据(包含自身)。

示例数据

id     title     parent_id
1      test      null
2      test1     1
3      test2     2

期望结果(查询id=3时)

[
 {
   "id": 1,
   "title": "test"
 },
 {
   "id": 2,
   "title": "test1"
 },
 {
   "id": 3,
   "title": "test2"
 }
]

之前尝试固定层级的join写法只能拿到部分父级;用Laravel关联loopParents能获取完整数据,但无法指定只查询特定字段,求可行的实现方案。


解决方案

方法1:MySQL递归CTE(推荐,MySQL 8.0+支持)

递归CTE可以动态遍历所有层级的父级,一次性查询出结果,效率远高于循环查询。

Laravel查询构造器实现:

$targetId = $this->main->id;

$allParents = DB::table('forum_categories')
    ->withRecursive(['cte' => function ($query) use ($targetId) {
        // 初始查询:获取目标分类自身
        $query->select('id', 'title', 'parent_id')
            ->from('forum_categories')
            ->where('id', $targetId);

        // 递归关联父级,直到parent_id为null
        $query->unionAll(function ($query) {
            $query->select('fc.id', 'fc.title', 'fc.parent_id')
                ->from('forum_categories as fc')
                ->join('cte', 'fc.id', '=', 'cte.parent_id');
        });
    }])
    ->select('id', 'title')
    ->from('cte')
    ->orderBy('id') // 按层级排序,根分类在前
    ->get();

该方法直接返回包含指定字段的完整父级集合,无需多次查询。

方法2:改进Laravel关联关系,支持指定字段

如果坚持用关联关系loopParents,可以通过指定查询字段实现需求:

  1. 先在Category模型中定义递归关联:
public function loopParents()
{
    return $this->belongsTo(Category::class, 'parent_id')
                ->with('loopParents'); // 开启递归关联
}
  1. 查询时指定字段(注意必须包含关联所需的id和parent_id):
$category = Category::where('id', $this->main->id)
    ->with(['loopParents' => function ($query) {
        $query->select('id', 'title', 'parent_id'); // 必须带parent_id才能继续递归
    }])
    ->select('id', 'title', 'parent_id') // 自身也要保留parent_id
    ->first();

// 整理自身和所有父级为指定字段的数组
$allParents = collect();
$current = $category;
while ($current) {
    $allParents->push($current->only('id', 'title'));
    $current = $current->loopParents;
}

// 可选:反转数组让根分类排在最前面
$allParents = $allParents->reverse()->values();

方法3:不推荐的固定层级join写法

你之前的join写法是固定了两层关联,只能适配固定层级的分类结构,无法处理动态变化的层级深度,因此不推荐使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 01:45:35