where_in()需配合非空数组使用,空数组会导致sql错误;distinct()仅对select字段去重,不可与*混用;查每组最新n条须用变量计数子查询,不能依赖where_in()+limit()。

where_in() 是查多条记录最常用也最容易出错的入口,别用 where() 硬塞数组。
查多条记录时,where_in() 必须配合非空数组使用
直接传空数组给 where_in('status', []) 会生成 WHERE status IN (),MySQL 报错或返回空结果;PostgreSQL 更严格,直接拒绝执行。实际业务中常因前端没传 ID、缓存未命中导致数组为空,必须提前拦截:
- 检查数组是否为
is_array($ids) && !empty($ids) - 强制转整型防注入:
$ids = array_map('intval', $ids) - 再调用:
$this->db->where_in('id', $ids)
查多条但只要字段值去重,用 distinct() 要注意字段范围
distinct() 不是“对整张表去重”,它只作用于 select() 明确列出的字段。比如写 $this->db->distinct()->select('*')->get('users'),多数数据库会报语法错误或忽略 DISTINCT —— 因为 * 展开后字段太多,无法确定去重依据。
- 正确写法:只选需要去重的字段,如
$this->db->distinct()->select('city, country') - 若需表达式去重(如邮箱域名),必须加别名:
$this->db->select("SUBSTRING_INDEX(email, '@', -1) as domain") -
distinct()可链式放在where()前或后,但建议放select()之前,语义更清晰
查多条并按每组取最新 N 条,不能靠 where_in() + limit()
$this->db->where_in('user_id', [101, 205, 317])->limit(10) 的结果是「总共最多 10 条」,不是「每个 user_id 各 10 条」。这是新手掉进最多的坑。
- CI 3.x 原生不支持
ROW_NUMBER() OVER (PARTITION BY ...),得手写变量子查询 - 核心逻辑:先
ORDER BY user_id, created_at DESC,再用@rn := IF(@prev = user_id, @rn + 1, 1)计数 - 务必显式列出字段,避免
SELECT *在子查询中引发歧义或性能问题
真正麻烦的不是语法,而是边界情况:空输入、类型混杂、字段别名缺失、子查询排序方向写反——这些地方一错,查出来的数据就静默错位,很难 debug。











