SQL ORDER BY DECODE是否将数字排序为字符串?

SQL ORDER BY DECODE是否将数字排序为字符串?,sql,oracle,sorting,sql-order-by,Sql,Oracle,Sorting,Sql Order By,我创建了一个飞行记录表,如下所示 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_ge

我创建了一个飞行记录表,如下所示

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
-------------------------------------------------
OR3237      01/03/16        9
RM7202      15/01/16        50
CQ8429      05/10/16        250
DA5720      21/07/16        100
出于某种原因,DECODE将数字列作为字符串进行排序。为了测试,我试过这个

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
证明问题不在于专栏本身

然后我尝试了一些我发现的解决方案

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拒绝将数字列作为数字进行排序呢?如何使其正确排序?

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

无论如何,您都应该使用用例。我首选的方法是多个语句:

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;

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

在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语句是相当容易的,每个SQL语句都有一个特定的ORDER BY子句,然后在输入参数上使用一个简单的IF-then-ELSE来确定要运行哪个SQL语句

,看起来很棒!会不会有一个性能的打击,虽然?因为看起来您正在进行3次单独的排序,而不是1次排序,即使其中2次排序始终为空。@sml485。请参阅附加答案中的我的回答。@sml485。不,没有额外的性能影响。按三个键排序与按一个键排序几乎相同。您的意思是说性能问题与用例或解码有关吗?我会根据输入使用不同的语句。然而,我的实际表有9列需要排序,其中包含一些相当复杂的聚合/联接。为了突出解码问题,我大大简化了这个问题。将它们分成9个独立的查询听起来像是维护地狱:@sml485。我的评论有点笼统。但我看到过非常复杂的SQL语句,开发人员试图巧妙地使用以下结构:SELECT*FROM emp,其中ename=:1或:1为NULL,job=:2或:2为NULL。问题是优化器无法确定谓词的选择性,因此,性能是次优的。所以我只是提醒大家使用超通用SQL语句。是的,您将有权权衡维护成本;但我还建议,更简单的SQL语句更易于调试和维护。