CodeIgniter中SQL查询DATE_FORMAT自动添加反引号报错问题
这个问题我碰到过好几次——CodeIgniter的Query Builder(原Active Record)默认会自动给select语句里的字段加反引号,用来规避SQL关键字冲突,但它误把DATE_FORMAT里的日期格式字符串当成了字段名,给它也套上了反引号,直接导致SQL语法报错。
下面给你几个靠谱的解决办法,按推荐程度排序:
方法1:关闭select的自动转义
直接给select()方法传第二个参数FALSE,告诉CI不要对整个select内容进行转义处理:
$this->db->select("DISTINCT(b.dname),DATE_FORMAT(atime,'%d %M %Y %h:%i:%s') as at", FALSE); // 注意:我去掉了格式字符串里的前置空格,避免日期前面多出不必要的空白 $this->db->join('rb b','b.list_id = al.afid','LEFT'); $this->db->from('rfal al'); $this->db->where('al.afid', $fileid); // 改成参数绑定写法,比直接拼接更安全 $this->db->where('al.is_back',1); $this->db->order_by('at','DESC'); $this->db->limit(5); $query= $this->db->get();
⚠️ 提示:用这个方法时,如果你的select里有需要转义的特殊字段,得手动加反引号;另外把原来的al.afid ='.$fileid改成参数绑定,能彻底避免SQL注入风险。
方法2:使用select_expr()专门处理表达式(CI3+适用)
CodeIgniter 3及以上版本提供了select_expr()方法,专门用来添加SQL表达式,不会自动转义,逻辑更清晰:
$this->db->select("DISTINCT(b.dname)"); // 第一个参数是SQL表达式,第二个是字段别名 $this->db->select_expr("DATE_FORMAT(atime,'%d %M %Y %h:%i:%s')", "at"); $this->db->join('rb b','b.list_id = al.afid','LEFT'); $this->db->from('rfal al'); $this->db->where('al.afid', $fileid); $this->db->where('al.is_back',1); $this->db->order_by('at','DESC'); $this->db->limit(5); $query= $this->db->get();
这种方式把普通字段和SQL表达式分开处理,可读性更强,也能避免误转义的问题。
方法3:直接使用原生SQL
如果Query Builder的方式让你觉得繁琐,直接写原生SQL也是个不错的选择,复杂查询时原生SQL反而更直观:
$sql = "SELECT DISTINCT(b.dname), DATE_FORMAT(atime,'%d %M %Y %h:%i:%s') as at FROM rfal al LEFT JOIN rb b ON b.list_id = al.afid WHERE al.afid = ? AND al.is_back = 1 ORDER BY at DESC LIMIT 5"; // 用参数绑定传递$fileid,避免SQL注入 $query = $this->db->query($sql, array($fileid));
这里用?作为占位符,把$fileid放到数组里传递,CI会自动帮你转义参数,既安全又能彻底规避格式字符串被误转义的问题。
为什么会出现这个问题?
CodeIgniter的Query Builder默认会解析select中的内容,尝试识别字段名并添加反引号,但它的解析逻辑不够智能,会把DATE_FORMAT里的字符串参数当成字段名,最终生成的SQL会变成:
SELECT DISTINCT(b.dname), DATE_FORMAT(atime,` %d %M %Y %h:%i:%s`) as at ...
这种带反引号的格式字符串在SQL里是非法的,自然会触发报错。
内容的提问来源于stack exchange,提问作者Preethi

