如何在PHP中用PDO通过单条SELECT语句关联父子数据?
嘿,我完全懂你想靠单条SELECT语句+PDO的fetchAll(PDO::FETCH_GROUP)来搞定父子层级数据的需求——毕竟比起先查父级再循环查子级的N+1查询,这种方式高效太多了!
你提到现在用FETCH_GROUP能得到分组结果,但父级都堆在0这个分组里,子级按对应父ID分组,确实这个结构不是我们想要的最终形态。那咱们来调整一下,把它转成父级数据带对应子级列表的结构:
第一步:用单条SQL获取所有数据并分组
先执行这条SQL查询所有数据,同时让PDO按parent_id分组:
// 执行查询,顺便按parent_id和id排序让结果更规整 $stmt = $pdo->query("SELECT * FROM earth ORDER BY parent_id, id"); // 用FETCH_GROUP按parent_id分组,同时用FETCH_ASSOC让结果是关联数组 $groupedData = $stmt->fetchAll(PDO::FETCH_GROUP | PDO::FETCH_ASSOC);
这时候$groupedData的结构是:
$groupedData[0]:所有父级数据(parent_id=0的记录)$groupedData[10]:parent_id=10的所有子级(也就是TREES的子项)$groupedData[11]:parent_id=11的所有子级(FLOWERS的子项)
第二步:重组数据为父级带子级的结构
接下来我们把父级和对应的子级整合到一起:
$finalResult = []; // 遍历所有父级数据 foreach ($groupedData[0] as $parent) { $parentId = $parent['id']; // 给父级添加children字段,对应它的子级(没有子级就设为空数组) $parent['children'] = $groupedData[$parentId] ?? []; $finalResult[] = $parent; }
现在$finalResult里的每个元素就是一个父级对象,自带children字段,里面是它的所有子级数据,完美符合你的需求!
为什么这个方法高效?
- 只需要一次数据库查询,彻底避免了N+1查询的性能问题
- PDO的
FETCH_GROUP是底层优化过的分组,比自己在PHP里循环分组要快 - 后续的重组逻辑非常轻量,几乎没什么性能开销
如果你想试试用JOIN的方式,也可以写这样的SQL,但会返回重复的父级数据,需要额外去重处理,反而不如上面的方法简洁:
SELECT p.*, c.id AS child_id, c.title AS child_title FROM earth p LEFT JOIN earth c ON p.id = c.parent_id WHERE p.parent_id = 0 ORDER BY p.id, c.id
但个人还是更推荐先分组再重组的方案,代码可读性和维护性都更好。
内容的提问来源于stack exchange,提问作者Divern
相关产品推荐
相关产品推荐

