MySql排序工作异常

时间:2017-02-27 09:20:58

标签: mysql sql

我编写了一个存储过程,它根据用户选择的列返回已排序(升序或降序)数据。 为实现这一点,我在 order by order 中使用了案例陈述,如下面的代码片段

ORDER BY 
    CASE WHEN p_filter_type = 'ASC' THEN
        CASE p_filter_column 
            WHEN 'projectCode' THEN projectCode -- varchar field
            WHEN 'visaType' THEN visaType -- varchar field
            WHEN 'approveRejectStatus' THEN `status` -- varchar field
            WHEN 'createdDate' THEN createdDate
            WHEN 'employeeID' THEN employeeId -- int field
            WHEN 'requestId' THEN requestId -- int field
            WHEN 'country' THEN country -- varchar field
            WHEN 'serviceDesk' THEN serviceDesk -- varchar field

    END
    END,
    CASE    WHEN p_filter_type = 'DESC' THEN
                CASE p_filter_column 
            WHEN 'projectCode' THEN projectCode -- varchar field
            WHEN 'visaType' THEN visaType -- varchar field
            WHEN 'approveRejectStatus' THEN `status` -- varchar field
            WHEN 'createdDate' THEN createdDate
            WHEN 'employeeID' THEN employeeId -- int field
            WHEN 'requestId' THEN requestId -- int field
            WHEN 'country' THEN country -- varchar field
            WHEN 'serviceDesk' THEN serviceDesk -- varchar field

    END
    END DESC
  

此代码中的问题是它不会正确排序数据(如果有的话)   选择具有整数数据类型的列。   它将整数值视为varchar并相应地对数据进行排序

例如 它返回

10
1
2
3

如果在 ASCENDING 顺序中选择 requestId

我尝试使用几个解决方案解决问题,例如使用ABS()将varchar值转换为整数等,但它们并没有帮我解决问题。

如果你们帮助我解决问题,我将不胜感激

6 个答案:

答案 0 :(得分:2)

实际上,当您组合不同的数据类型时,即使 p_filter_type p_filter_column 指示只有数字列,表达式也会转换为varchar应该确定该表达的结果。

解决此问题的一种方法是为每种可能性创建单独的order by表达式,为所有这些表达式生成null,除了相关的表达式。这样每个表达式都可以坚持自己的数据类型:

ORDER BY 
    CASE WHEN p_filter_type = 'ASC' AND p_filter_column = 'projectCode' 
        THEN projectcode END ASC,
    CASE WHEN p_filter_type = 'ASC' AND p_filter_column = 'visaType' 
        THEN visaType END ASC,
    CASE WHEN p_filter_type = 'ASC' AND p_filter_column = 'approveRejectStatus' 
        THEN status END ASC,
    CASE WHEN p_filter_type = 'ASC' AND p_filter_column = 'createdDate'
        THEN createdDate END ASC,
    CASE WHEN p_filter_type = 'ASC' AND p_filter_column = 'employeeID'
        THEN employeeID END ASC,
    CASE WHEN p_filter_type = 'ASC' AND p_filter_column = 'requestId'
        THEN requestId END ASC,
    CASE WHEN p_filter_type = 'ASC' AND p_filter_column = 'country'
        THEN country END ASC,
    CASE WHEN p_filter_type = 'ASC' AND p_filter_column = 'serviceDesk'
        THEN serviceDesk END ASC,
    CASE WHEN p_filter_type = 'DESC' AND p_filter_column = 'projectCode' 
        THEN projectcode END DESC,
    CASE WHEN p_filter_type = 'DESC' AND p_filter_column = 'visaType' 
        THEN visaType END DESC,
    CASE WHEN p_filter_type = 'DESC' AND p_filter_column = 'approveRejectStatus' 
        THEN status END DESC,
    CASE WHEN p_filter_type = 'DESC' AND p_filter_column = 'createdDate'
        THEN createdDate END DESC,
    CASE WHEN p_filter_type = 'DESC' AND p_filter_column = 'employeeID'
        THEN employeeID END DESC,
    CASE WHEN p_filter_type = 'DESC' AND p_filter_column = 'requestId'
        THEN requestId END DESC,
    CASE WHEN p_filter_type = 'DESC' AND p_filter_column = 'country'
        THEN country END DESC,
    CASE WHEN p_filter_type = 'DESC' AND p_filter_column = 'serviceDesk'
        THEN serviceDesk END DESC

例如,当p_filter_type = 'DESC'p_filter_column = 'employeeID'时,上述ORDER BY条款确实解析为以下内容:

ORDER BY 
    NULL ASC,
    NULL ASC,
    NULL ASC,
    NULL ASC,
    NULL ASC,
    NULL ASC,
    NULL ASC,
    NULL ASC,
    NULL DESC,
    NULL DESC,
    NULL DESC,
    NULL DESC,
    employeeID DESC,
    NULL DESC,
    NULL DESC,
    NULL DESC

应该像你刚刚写的那样订购:

ORDER BY 
    employeeID DESC

混合解决方案

当然,你可以选择一个中间解决方案,在这个解决方案中,将一个表达式中具有相同数据类型的字段组合在一起,这样就不会发生数据类型转换。这样,您的order by子句中可能有6个表达式:一个用于varchar个字段,一个用于int字段,一个用于date字段,然后每个都重复对于降序案例:

ORDER BY 
    CASE WHEN p_filter_type = 'ASC' THEN
        CASE p_filter_column -- all varchar fields
            WHEN 'projectCode' THEN projectCode
            WHEN 'visaType' THEN visaType
            WHEN 'approveRejectStatus' THEN status
            WHEN 'country' THEN country
            WHEN 'serviceDesk' THEN serviceDesk
        END
    END ASC,
    CASE WHEN p_filter_type = 'ASC' THEN
        CASE p_filter_column -- all int fields 
            WHEN 'employeeID' THEN employeeId
            WHEN 'requestId' THEN requestId
        END
    END ASC,
    CASE WHEN p_filter_type = 'ASC' THEN
        CASE p_filter_column -- all date fields
            WHEN 'createdDate' THEN createdDate
        END
    END ASC,
    CASE WHEN p_filter_type = 'DESC' THEN
        CASE p_filter_column -- all varchar fields
            WHEN 'projectCode' THEN projectCode
            WHEN 'visaType' THEN visaType
            WHEN 'approveRejectStatus' THEN status
            WHEN 'country' THEN country
            WHEN 'serviceDesk' THEN serviceDesk
        END
    END DESC,
    CASE WHEN p_filter_type = 'DESC' THEN
        CASE p_filter_column -- all int fields 
            WHEN 'employeeID' THEN employeeId
            WHEN 'requestId' THEN requestId
        END
    END DESC,
    CASE WHEN p_filter_type = 'DESC' THEN
        CASE p_filter_column -- all date fields
            WHEN 'createdDate' THEN createdDate
        END
    END DESC

答案 1 :(得分:0)

如何将ASC订单添加到第一个案例?

SELECT    b.*
FROM      B b
WHERE     b.id = a.id
AND       b.modified_date > a.modified.date

有用吗?此外,您确定您用作错误排序示例的日期不在Varchar列中吗?它看起来像一个人一样。

答案 2 :(得分:0)

如果你只想将varchar值转换为整数,假设这些值是数字,mysql可以简单地做到,让这个列加0,如下所示:

ORDER BY 
    CASE WHEN p_filter_type = 'ASC' THEN
        CASE p_filter_column 
            WHEN 'projectCode' THEN projectCode -- varchar field
            WHEN 'visaType' THEN visaType -- varchar field
            WHEN 'approveRejectStatus' THEN `status` -- varchar field
            WHEN 'createdDate' THEN createdDate
            WHEN 'employeeID' THEN employeeId -- int field
            WHEN 'requestId' THEN requestId + 0 -- int field
            WHEN 'country' THEN country -- varchar field
            WHEN 'serviceDesk' THEN serviceDesk -- varchar field

    END
    END,
    CASE    WHEN p_filter_type = 'DESC' THEN
                CASE p_filter_column 
            WHEN 'projectCode' THEN projectCode -- varchar field
            WHEN 'visaType' THEN visaType -- varchar field
            WHEN 'approveRejectStatus' THEN `status` -- varchar field
            WHEN 'createdDate' THEN createdDate
            WHEN 'employeeID' THEN employeeId -- int field
            WHEN 'requestId' THEN requestId + 0 -- int field
            WHEN 'country' THEN country -- varchar field
            WHEN 'serviceDesk' THEN serviceDesk -- varchar field

    END
    END DESC

在sqlfiddle中查看简单的demo

答案 3 :(得分:0)

ORDER BY 
    CASE WHEN p_filter_type = 'ASC' THEN
        CASE p_filter_column 
            WHEN 'projectCode' THEN CAST(projectCode AS INT) -- varchar field
            WHEN 'visaType' THEN CAST(visaType AS INT) -- varchar field
            WHEN 'approveRejectStatus' THEN CAST(status AS INT) -- varchar field
            WHEN 'createdDate' THEN createdDate
            WHEN 'employeeID' THEN employeeId -- int field
            WHEN 'requestId' THEN requestId -- int field
            WHEN 'country' THEN CAST(country AS INT) -- varchar field
            WHEN 'serviceDesk' THEN CAST(serviceDesk AS INT) -- varchar field

    END
    END,
    CASE    WHEN p_filter_type = 'DESC' THEN
                CASE p_filter_column 
           WHEN 'projectCode' THEN CAST(projectCode AS INT) -- varchar field
            WHEN 'visaType' THEN CAST(visaType AS INT) -- varchar field
            WHEN 'approveRejectStatus' THEN CAST(status AS INT) -- varchar field
            WHEN 'createdDate' THEN createdDate
            WHEN 'employeeID' THEN employeeId -- int field
            WHEN 'requestId' THEN requestId -- int field
            WHEN 'country' THEN CAST(country AS INT) -- varchar field
            WHEN 'serviceDesk' THEN CAST(serviceDesk AS INT) -- varchar field

    END
    END DESC

我认为由于varchar类型的列包含数字,并且您希望根据数字对此字段进行排序,因此您需要在排序期间将该VARCHAR字段转换为INT,就像我在上面的代码中尝试过的那样。 希望这会对你有所帮助。

答案 4 :(得分:0)

由于CASE返回原子值,因此返回的数据类型只能是单个。在不同的执行中,您不能具有不同的返回数据类型。在这种情况下,所有内容都被隐式转换为varchar。为了获得您想要的订单,您必须确保整数将根据字符串排序规则进行排序。像这样:

CASE WHEN p_filter_type = 'ASC' THEN
        CASE p_filter_column 
            WHEN 'projectCode' THEN projectCode -- varchar field
            WHEN 'visaType' THEN visaType -- varchar field
            WHEN 'approveRejectStatus' THEN `status` -- varchar field
            WHEN 'createdDate' THEN createdDate
            WHEN 'employeeID' THEN RIGHT(CONCAT('00', employeeId), 2) -- int field
            WHEN 'requestId' THEN RIGHT(CONCAT('00', requestId), 2) -- int field
            WHEN 'country' THEN country -- varchar field
            WHEN 'serviceDesk' THEN serviceDesk -- varchar field
        END
END

对于排序,它会将值更改为01, 02, 03, 10,这将按您希望的方式排序。

我不确定您的日期是否会被正确订购,这取决于您当地的设置。

答案 5 :(得分:0)

您可以使用CONCAT函数生成预准备语句:

SET @sql = CONCAT('select * from some_table order by ', p_filter_column, ' ', p_filter_type);
PREPARE stmt FROM @sql;
EXECUTE stmt;

作为奖励,预备语句可以使用索引(如果已定义)。

但是,您可能需要先验证输入。

另一种解决方法可能是将LPAD用于数字字段并用零填充数字:

WHEN 'employeeID' THEN LPAD(employeeId, 20, '0') -- int field

但它只适用于UNSIGNED类型。