
本文详解如何在 CodeIgniter 中高效实现“为数组中每个 userId 获取其最新的 10 条交易记录”,突破 where_in() + 全局 limit() 的局限,借助 MySQL 变量模拟窗口函数(ROW_NUMBER),确保结果精准、可扩展且兼容 CI 3.x 常用版本。
本文详解如何在 codeigniter 中高效实现“为数组中每个 userid 获取其最新的 10 条交易记录”,突破 `where_in()` + 全局 `limit()` 的局限,借助 mysql 变量模拟窗口函数(row_number),确保结果精准、可扩展且兼容 ci 3.x 常用版本。
在实际开发中,常需对一组用户(如 $userIds = [101, 205, 317])分别拉取各自最近 N 条操作记录(如交易、日志、订单)。CodeIgniter 原生 Query Builder 不支持标准 SQL 的 ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...) 语法(尤其在 MySQL 5.7 及更早版本),因此无法直接通过链式调用实现“每组限条”。此时,推荐采用 MySQL 用户变量 + 子查询 的经典方案——它逻辑清晰、性能可控,且完全适配 CodeIgniter 的 $this->db->query() 接口。
以下为优化后的模型方法实现(兼容 MySQL 5.6+,已做安全加固):
function getTrans($cData, $date = 0) {
// 1. 输入校验:确保 $cData 是非空数组,且元素均为整型
if (!is_array($cData) || empty($cData)) {
return [];
}
// 2. 安全转义用户 ID 数组(防止 SQL 注入)
$escapedIds = array_map([$this->db, 'escape'], $cData);
$idsString = implode(', ', $escapedIds);
// 3. 构建带变量的分组排序子查询
$sql = "
SELECT id, userId, date, amount, type -- 显式列出字段,避免 * 带来歧义
FROM (
SELECT
trans.*,
@rn := IF(@prev_user = userId, @rn + 1, 1) AS rank,
@prev_user := userId
FROM trans
CROSS JOIN (SELECT @prev_user := 0, @rn := 0) AS init
WHERE userId IN ({$idsString})
" . ($date ? "AND date >= " . $this->db->escape($date) : "") . "
ORDER BY userId, id DESC -- 注意:按 id 降序 → 获取「最新」记录
) ranked
WHERE rank <= 10
ORDER BY userId, id DESC;
";
$query = $this->db->query($sql);
return $query->num_rows() > 0 ? $query->result() : [];
}✅ 关键设计说明:
- 变量初始化:CROSS JOIN (SELECT @prev_user := 0, @rn := 0) 确保每次查询变量从零开始,避免会话级残留影响;
- 排序逻辑:ORDER BY userId, id DESC 是核心——先按 userId 分组,再按 id(或时间字段)降序,保证 @rn 递增顺序对应“最新优先”;
- 字段显式声明:避免使用 SELECT *,既提升可读性,也防止因表结构变更导致结果错位;
- SQL 注入防护:全程使用 $this->db->escape() 处理动态值,$date 同样被转义,杜绝安全风险;
- 空数组兜底:前置校验避免生成无效 SQL(如 IN () 报错)。
⚠️ 注意事项:
- 此方案依赖 MySQL 用户变量行为,在 MySQL 8.0+ 中虽仍可用,但官方建议优先迁移到原生 ROW_NUMBER()(需调整 SQL 结构);
- 若 trans 表数据量极大(千万级),务必为 (userId, id) 或 (userId, date) 建立复合索引,否则 ORDER BY 将成为性能瓶颈;
- CodeIgniter 4 用户可直接使用原生 PDO + 窗口函数,无需变量模拟,但本方案在 CI 3.x 生产环境经大量验证,稳定可靠。
总结而言,当 Query Builder 功能受限时,合理使用 $this->db->query() 执行定制化 SQL 是务实之选。该实现以最小侵入方式解决“每组 Top-N”这一高频需求,兼顾正确性、安全性与可维护性,可直接集成至现有模型中复用。










