Codeigniter:ORDER BY CASE 查询中的错误
Posted
技术标签:
【中文标题】Codeigniter:ORDER BY CASE 查询中的错误【英文标题】:Codeigniter : Error in ORDER BY CASE query 【发布时间】:2014-09-23 10:50:59 【问题描述】:这是我在 Codeigniter
中的查询$this->db->select('p.*,u.firstname, u.lastname,s.title AS industry, pt.type_name , al.length_value',FALSE);
$this->db->from($this->_tbl_projects . ' as p');
$this->db->join($this->_tbl_client_details . ' as c', 'c.id = p.client_id', 'left');
$this->db->join($this->_tbl_users . ' as u', 'u.id = c.user_id', 'left');
$this->db->join($this->_tbl_project_types . ' as pt', 'pt.project_type_id = p.project_type_id', 'left');
$this->db->join($this->_tbl_specializations . ' as s', 's.specialization_id = p.specialization_id', 'left');
$this->db->join($this->_tbl_article_length . ' as al', 'al.article_length_id = p.article_length_id', 'left');
$this->db->order_by("CASE p.submit_to
WHEN '' THEN 0
WHEN 'writer' THEN 1
ELSE 2
END, p.request_end_date asc",FALSE);
打印出来
SELECT p.*, u.firstname, u.lastname, s.title AS industry, pt.type_name, al.length_value
FROM (`projects` as p)
LEFT JOIN `client_details` as c ON `c`.`id` = `p`.`client_id`
LEFT JOIN `users` as u ON `u`.`id` = `c`.`user_id`
LEFT JOIN `project_types` as pt ON `pt`.`project_type_id` = `p`.`project_type_id`
LEFT JOIN `specializations` as s ON `s`.`specialization_id` = `p`.`specialization_id`
LEFT JOIN `article_length` as al ON `al`.`article_length_id` = `p`.`article_length_id` WHERE `p`.`client_id` = '26' AND `p`.`status` IN (2, 3)
ORDER BY
`CASE` p.submit_to
WHEN '' THEN 0
WHEN 'writer' THEN 1
ELSE 2
END, `p`.`request_end_date` asc
这里在打印查询中,CASE是由`CASE`打印的,所以sql会抛出错误。
我该如何解决?
submit_to 字段的结构是
submit_to enum('','writer','students') NOT NULL
【问题讨论】:
【参考方案1】:CodeIgniter 文档指出,在 Active Record 类中不支持 order by 子句中的 case 语句。我建议重构 SQL 调用,使 case 语句成为 select 子句的一部分。像下面这样的东西应该可以解决问题。
$this->db->select("p.*,u.firstname, u.lastname,s.title AS industry, pt.type_name, al.length_value, CASE p.submit_to WHEN 'writer' THEN 2 WHEN 'students' THEN 1 ELSE 0 END AS ordered_submit_to",FALSE);
$this->db->from($this->_tbl_projects . ' as p');
$this->db->join($this->_tbl_client_details . ' as c', 'c.id = p.client_id', 'left');
$this->db->join($this->_tbl_users . ' as u', 'u.id = c.user_id', 'left');
$this->db->join($this->_tbl_project_types . ' as pt', 'pt.project_type_id = p.project_type_id', 'left');
$this->db->join($this->_tbl_specializations . ' as s', 's.specialization_id = p.specialization_id', 'left');
$this->db->join($this->_tbl_article_length . ' as al', 'al.article_length_id = p.article_length_id', 'left');
$this->db->order_by('ordered_submit_to', 'ASC');
$this->db->order_by('p.request_end_date', 'ASC');
【讨论】:
感谢您的回答。您的更新有效,但没有以正确的顺序给出结果。我想要数据以 submit_to = '' 然后 submit_to = 'students' 和最后 submit_to = 'writer'。您的更新按以下顺序给出结果 1. '' 2. 'writer' 3. 'students'。 已更新以匹配您重述的订单。【参考方案2】:我在another answer on SO 找到了一个很好的解决方案,所以如果你登陆了这个页面但还没有找到那个,我会在这里重新发布。
如果您将 case 语句括在括号中,则可以使用 case 语句。
$this->db->order_by("
(CASE p.submit_to
WHEN '' THEN 0
WHEN 'writer' THEN 1
ELSE 2
END),
p.request_end_date asc"
);
【讨论】:
【参考方案3】:我想出了如何避免转义 CASE 字。
您可以在 CI_DB_driver 类中修改 $_reserved_identifiers 变量。如果您不想修改整个文件,只需在查询之前在 Model 类中更改它即可。
$this->db->_reserved_identifiers = array('*','CASE');
$this->db->select('p.*,u.firstname, u.lastname,s.title AS industry, pt.type_name , al.length_value',FALSE);
$this->db->from($this->_tbl_projects . ' as p');
$this->db->join($this->_tbl_client_details . ' as c', 'c.id = p.client_id', 'left');
$this->db->join($this->_tbl_users . ' as u', 'u.id = c.user_id', 'left');
$this->db->join($this->_tbl_project_types . ' as pt', 'pt.project_type_id = p.project_type_id', 'left');
$this->db->join($this->_tbl_specializations . ' as s', 's.specialization_id = p.specialization_id', 'left');
$this->db->join($this->_tbl_article_length . ' as al', 'al.article_length_id = p.article_length_id', 'left');
$this->db->order_by("CASE p.submit_to
WHEN '' THEN 0
WHEN 'writer' THEN 1
ELSE 2
END, p.request_end_date asc",FALSE);
(我不知道它是否在 3.x 分支上运行。它在 2.x 分支上运行良好)
【讨论】:
【参考方案4】:我今天测试了,它工作正常。
当你使用第二个参数 FALSE 禁用转义时,你可以像你说的那样使用它。
$this->db->order_by("CASE p.submit_to
WHEN '' THEN 0
WHEN 'writer' THEN 1
ELSE 2
END, p.request_end_date asc",FALSE);
您好。
【讨论】:
【参考方案5】:在“SELECT”而不是“ORDER_BY”中设置“CASE WHEN”:
$this->db->select('p.*,u.firstname, u.lastname,s.title AS industry, pt.type_name , al.length_value',FALSE);
$this->db->select("CASE p.submit_to WHEN '' THEN 0 WHEN 'writer' THEN 1 ELSE 2 END order_column_number",FALSE);
$this->db->from($this->_tbl_projects . ' as p');
$this->db->join($this->_tbl_client_details . ' as c', 'c.id = p.client_id', 'left');
$this->db->join($this->_tbl_users . ' as u', 'u.id = c.user_id', 'left');
$this->db->join($this->_tbl_project_types . ' as pt', 'pt.project_type_id = p.project_type_id', 'left');
$this->db->join($this->_tbl_specializations . ' as s', 's.specialization_id = p.specialization_id', 'left');
$this->db->join($this->_tbl_article_length . ' as al', 'al.article_length_id = p.article_length_id', 'left');
$this->db->order_by("order_column_number ASC, p.request_end_date ASC");
【讨论】:
以上是关于Codeigniter:ORDER BY CASE 查询中的错误的主要内容,如果未能解决你的问题,请参考以下文章
CodeIgniter 在使用 insert()、update()、where()、order_by() 等函数时会自动阻止 SQL 注入吗?