【问题标题】:SQL ORDER BY DECODE is sorting number as a string?SQL ORDER BY DECODE 将数字排序为字符串?
【发布时间】:2017-02-10 03:24:14
【问题描述】:

我有一个如下创建的飞行记录表

CREATE TABLE FLIGHT_DETAILS
(
FLIGHT_ID           NUMBER(10) PRIMARY KEY,
FLIGHT_NO           VARCHAR2(10),
DEPARTURE_DTE       DATE,
TOTAL_PASSENGERS    NUMBER(3)
);

然后,我的应用程序调用了一个函数来检索按所选列排序的记录(按降序排列)。

CREATE OR REPLACE FUNCTION func_get_flight_details (

p_order_col IN CHAR )

RETURN sys_refcursor
AS
    v_ref_cursor    sys_refcursor;
    v_sql_str       VARCHAR2(2048);
BEGIN
OPEN v_ref_cursor FOR

SELECT FLIGHT_NO, DEPARTURE_DTE, TOTAL_PASSENGERS 
FROM FLIGHT_DETAILS
ORDER BY DECODE(p_order_col,
        'FLIGHT_NO', FLIGHT_NO,
        'DEPARTURE_DTE', TO_DATE(DEPARTURE_DTE, 'YYYY/MM/DD'),
        'TOTAL_PASSENGERS', TOTAL_PASSENGERS) DESC;

RETURN v_ref_cursor;
END;

按FLIGHT_NO 和DEPARTURE_DTE 排序可以正常工作。当我尝试按TOTAL_PASSENGERS 排序时,我的问题就出现了,这让我得到了这个

FLIGHT_NO   DEPARTURE_DTE   TOTAL_PASSENGERS
-------------------------------------------------
OR3237      01/03/16        9
RM7202      15/01/16        50
CQ8429      05/10/16        250
DA5720      21/07/16        100

出于某种原因,DECODE 将NUMBER 列排序为字符串。为了测试,我尝试了这个

SELECT FLIGHT_NO, DEPARTURE_DTE, TOTAL_PASSENGERS 
FROM FLIGHT_DETAILS
ORDER BY TOTAL_PASSENGERS DESC;

这给了我

FLIGHT_NO   DEPARTURE_DTE   TOTAL_PASSENGERS
-------------------------------------------------
CQ8429      05/10/16        250
DA5720      21/07/16        100
RM7202      15/01/16        50
OR3237      01/03/16        9

证明问题不在于专栏本身。

然后我尝试了一些我在 SO 上找到的解决方案

ORDER BY DECODE(p_order_col,
        'FLIGHT_NO', FLIGHT_NO,
        'DEPARTURE_DTE', TO_DATE(DEPARTURE_DTE, 'YYYY/MM/DD'),
        'TOTAL_PASSENGERS', TO_NUMBER(TOTAL_PASSENGERS)) DESC;


ORDER BY DECODE(p_order_col,
        'FLIGHT_NO', FLIGHT_NO,
        'DEPARTURE_DTE', TO_DATE(DEPARTURE_DTE, 'YYYY/MM/DD'),
        'TOTAL_PASSENGERS', LPAD(TOTAL_PASSENGERS, 10)) DESC;


ORDER BY DECODE(p_order_col,
        'FLIGHT_NO', FLIGHT_NO,
        'DEPARTURE_DTE', TO_DATE(DEPARTURE_DTE, 'YYYY/MM/DD'),
        'TOTAL_PASSENGERS', TOTAL_PASSENGERS*1) DESC;

这些都不起作用(它仍然作为字符串排序)。

那么为什么DECODE 拒绝将数字列作为数字进行排序呢?以及如何让它正确排序?

【问题讨论】:

    标签: sql oracle sorting sql-order-by


    【解决方案1】:

    您的问题是 decode() 是一个表达式,并且只返回一种类型。因此,必须转换类型。

    无论如何你都应该使用case。我的首选方法是多语句:

    ORDER BY (CASE WHEN p_order_col = 'FLIGHT_NO' THEN FLIGHT_NO END),
             (CASE WHEN p_order_col = 'DEPARTURE_DTE' THEN TO_DATE(DEPARTURE_DTE, 'YYYY/MM/DD') END)
             (CASE WHEN p_order_col = 'TOTAL_PASSENGERS' THEN TOTAL_PASSENGERS END) DESC;
    

    每个表达式按一个键排序。如果排序键不匹配,则表达式的结果为NULL——所有行都得到相同的值,因此不影响排序。

    【讨论】:

    • 看起来很棒!会不会对性能造成影响?因为看起来您正在执行 3 个单独的排序而不是 1 个(即使其中 2 个始终是 null。
    • @sml485。在附加答案中查看我的回复。
    • @sml485 。 . .不,没有额外的性能影响。三键排序与一键排序几乎相同。
    【解决方案2】:

    Gordon 发布的示例答案对性能几乎没有影响。你并没有真正做 3 种不同的分类;它仍然是一个单一的排序操作。快速测试会显示:

    select ename, sal, mgr 
    from emp 
    order by ( case when 'SAL' = 'SAL' then sal end ) 
    ,        ( case when 'SAL' = 'NAME' then ename end )
    
    -----------------------------------------------------------------------------------
    | Id  | Operation                  | Name | Rows  | Bytes | Cost (%CPU)| Time     |
    -----------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT           |      |       |       |    21 (100)|          |
    |   1 |  SORT ORDER BY             |      |    14 |   196 |    21  (10)| 00:00:01 |
    |   2 |   TABLE ACCESS STORAGE FULL| EMP  |    14 |   196 |    20   (5)| 00:00:01 |
    -----------------------------------------------------------------------------------
    

    但是,我会提醒您尝试编写单个“通用”SQL 语句来处理各种不同情况的方法。虽然这种“聪明”的 SQL 语句可以正常工作,但它可能对性能造成灾难。最好有一个单独的 SQL 语句。在这里发布的这个例子中,拥有三个不同的 SQL 语句是相当容易的,每个语句都有一个特定的ORDER BY 子句,然后在输入参数上使用一个简单的IF THEN ELSE 来确定要运行哪个 SQL 语句

    【讨论】:

    • 您的意思是使用case 或decode 会带来性能问题吗?我根据输入使用单独的语句。然而,我的实际表有 9 列可供排序,其中包含一些相当复杂的聚合/连接。我为这个问题大大简化了它以突出decode 问题。将它们分成 9 个单独的查询听起来像是维护地狱:(
    • @sml485。我的评论有点笼统。但是我看到了非常复杂的 SQL 语句,开发人员试图变得聪明,其结构如下:SELECT * FROM emp WHERE (ename = :1 OR :1 IS NULL) 和 (job = :2 OR :2 IS NULL) .问题是优化器无法确定谓词的选择性,因此,性能是次优的。所以我只是提醒使用“超级通用”的 SQL 语句。是的,您将权衡维护成本;但我也建议更简单的 SQL 语句更易于调试和维护。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-10-15
    • 2022-01-07
    • 2014-10-12
    • 2012-01-23
    • 1970-01-01
    • 2022-12-09
    相关资源
    最近更新 更多