CodeIgniter中MySQL用户变量失效:分组排名全为1问题排查
问题原因分析
这个问题的核心是MySQL用户变量未正确初始化,再加上CodeIgniter的数据库执行逻辑导致变量上下文没有正确延续。
当你直接在MySQL客户端执行这条查询时,要么你的会话里之前已经存在@topic_rank和@current_category变量(哪怕是默认的NULL,但客户端会话会持续整个查询过程),要么你无意中在同一会话里完成了变量的隐式初始化。但在CodeIgniter里情况不一样:
- 默认情况下,
@topic_rank和@current_category的初始值是NULL,没有提前被赋值。 - 每一行执行
IF(@current_category = category_name, ...)判断时,NULL和任何category_name都不相等,所以每次都会触发@topic_rank := 1,最终所有记录的排名都变成了1。
解决方案
这里有两种可靠的解决方式,推荐第一种更稳妥的方案:
方法1:在查询语句内初始化变量
把变量初始化逻辑和查询合并到同一条SQL里,确保变量在查询启动时就被正确设置:
$query = " SELECT category_name, topic_title, updated_ts, @topic_rank := IF(@current_category = category_name, @topic_rank + 1, 1) AS topic_rank, @current_category := category_name AS current_category FROM topic_master, (SELECT @topic_rank := 0, @current_category := '') AS init_vars ORDER BY category_name, updated_ts DESC "; $data = $this->db->query($query); return $data->num_rows() > 0 ? $data : false;
这里通过子查询(SELECT @topic_rank := 0, @current_category := '') AS init_vars,在查询开始时就完成了两个变量的初始化,确保排名逻辑能正常运行。
方法2:分两次执行SQL(先初始化变量,再查排名)
如果不想修改主查询结构,可以先单独执行变量初始化语句,再执行排名查询:
// 先初始化排名变量 $this->db->query("SET @topic_rank = 0, @current_category = ''"); // 再执行排名查询 $query = " SELECT category_name, topic_title, updated_ts, @topic_rank := IF(@current_category = category_name, @topic_rank + 1, 1) AS topic_rank, @current_category := category_name AS current_category FROM topic_master ORDER BY category_name, updated_ts DESC "; $data = $this->db->query($query); return $data->num_rows() > 0 ? $data : false;
注意:这种方法依赖CodeIgniter保持同一个数据库连接(默认是持久连接,一般没问题),如果是短连接场景可能会失效,所以更推荐第一种方法。
额外小提示
你原来代码里用affected_rows()判断结果是否存在不太合适,affected_rows()主要用于INSERT/UPDATE/DELETE这类修改数据的语句,对于SELECT查询,应该用num_rows()来判断是否有返回结果。
内容的提问来源于stack exchange,提问作者Ganesh T
相关产品推荐
相关产品推荐

