CodeIgniter 4 如何用构建器或原生查询获取当前条目前后相邻行
代码修正与功能实现方案
基础问题修正
原代码存在两个直接影响运行的问题:
- 未初始化
$builder实例,未绑定查询主表,直接调用会触发未定义类的报错 - 直接将传入参数
$qs拼接到SQL语句中,存在SQL注入风险
功能实现逻辑
要拿到目标条目的相邻关联数据,核心是先通过目标ID定位排序锚点(基于segments_en的自增主键作为稳定排序依据,避免顺序错乱),再按同归属的tape字段圈定范围,拉取锚点前后指定数量的记录即可。
CodeIgniter4 查询构建器实现版本
可直接运行的修正后代码如下:
public function show_questions($qs = false) { $db = \Config\Database::connect(); // 参数有效性校验 if (!$qs || !is_numeric($qs)) { return []; } // 初始化绑定questions_en表的查询构建器 $builder = $db->table('questions_en'); // 第一步:定位目标条目的锚点值 $anchor = $builder->select('questions_en.tape, segments_en.segment_id') ->join('segments_en', 'questions_en.tape = segments_en.tape') ->where('questions_en.question_id', $qs) ->get() ->getRowArray(); // 目标条目不存在直接返回空数组 if (!$anchor) { return []; } // 第二步:拉取锚点前后各3条同tape的关联记录 $neighborList = $builder->select('*') ->join('segments_en', 'questions_en.tape = segments_en.tape') ->where('segments_en.tape', $anchor['tape']) // 调整以下两个边界值即可灵活控制前后取数的条数,比如前2后3就把-3改成-2 ->where('segments_en.segment_id >=', $anchor['segment_id'] - 3) ->where('segments_en.segment_id <=', $anchor['segment_id'] + 3) ->orderBy('segments_en.segment_id', 'ASC'); return $neighborList->get()->getResultArray(); }
原生查询实现版本
如果偏好原生SQL写法,可使用CI4支持的参数绑定原生查询逻辑:
public function show_questions($qs = false) { $db = \Config\Database::connect(); if (!$qs || !is_numeric($qs)) { return []; } // 先查出锚点值,计算范围边界 $anchor = $db->query( "SELECT s2.segment_id FROM questions_en q2 JOIN segments_en s2 ON q2.tape = s2.tape WHERE q2.question_id = ? LIMIT 1", [$qs] )->getRowArray(); if (!$anchor) { return []; } $sql = " SELECT * FROM questions_en q JOIN segments_en s ON q.tape = s.tape WHERE q.tape = ( SELECT q2.tape FROM questions_en q2 JOIN segments_en s2 ON q2.tape = s2.tape WHERE q2.question_id = ? LIMIT 1 ) AND s.segment_id BETWEEN ? AND ? ORDER BY s.segment_id ASC "; $startId = $anchor['segment_id'] - 3; $endId = $anchor['segment_id'] + 3; return $db->query($sql, [$qs, $startId, $endId])->getResultArray(); }
实现说明
- 返回结果天然包含目标条目本身,前后各覆盖最多3条相邻记录;如果靠前/靠后方向没有足够的记录,会自动返回实际存在的条目,不需要额外的空值兼容逻辑
- 调整两个边界计算的数值,即可灵活实现“前2条后3条”这类差异化取数需求
- 生产环境建议给
segments_en表加(tape, segment_id)的联合索引,大范围查询时性能会有明显提升
内容的提问来源于stack exchange,提问作者AviR
相关产品推荐
相关产品推荐

