SQL ORDER BY DECODE 是将数字作为字符串排序吗?
SQL ORDER BY DECODE is sorting number as a string?
我有一个 table 飞行记录创建如下
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;
none 其中有效(仍按字符串排序)。
那么为什么 DECODE
拒绝将数字列作为数字进行排序?我如何让它正确排序?
你的问题是 decode()
是一个表达式并且只有 returns 一种类型。因此,必须转换类型。
无论如何你应该使用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
——所有行都获得相同的值,因此不会影响排序。
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 |
-----------------------------------------------------------------------------------
但是我要提醒您尝试编写单个 "generic" SQL 语句来处理各种不同情况的方法。虽然这种 "clever" SQL 语句在功能上可以工作,但对性能来说可能是一场灾难。最好有一个单独的 SQL 语句。在此处发布的这个示例中,拥有三个不同的 SQL 语句非常容易,每个语句都有一个特定的 ORDER BY
子句,然后在输入参数上使用简单的 IF THEN ELSE
来确定哪个SQL 语句 运行
我有一个 table 飞行记录创建如下
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;
none 其中有效(仍按字符串排序)。
那么为什么 DECODE
拒绝将数字列作为数字进行排序?我如何让它正确排序?
你的问题是 decode()
是一个表达式并且只有 returns 一种类型。因此,必须转换类型。
无论如何你应该使用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
——所有行都获得相同的值,因此不会影响排序。
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 |
-----------------------------------------------------------------------------------
但是我要提醒您尝试编写单个 "generic" SQL 语句来处理各种不同情况的方法。虽然这种 "clever" SQL 语句在功能上可以工作,但对性能来说可能是一场灾难。最好有一个单独的 SQL 语句。在此处发布的这个示例中,拥有三个不同的 SQL 语句非常容易,每个语句都有一个特定的 ORDER BY
子句,然后在输入参数上使用简单的 IF THEN ELSE
来确定哪个SQL 语句 运行