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 注入吗?

Codeigniter order_by 名称不起作用

在 ORDER BY 中使用 CASE 语句

MySQL ORDER BY CASE 优化

ORDER BY 子句的 CASE WHEN 语句

Oracle order by case when 多条件排序