2017-02-10 103 views
2

我有創造的飛行記錄的表如下SQL ORDER BY DECODE將數字排序爲字符串?

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_NODEPARTURE_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拒絕將數字列作爲數字進行排序呢?我如何才能正確排序?

回答

2

你的問題是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 - 所有行的值都相同,因此不會影響排序。

+0

看起來很棒!那會不會有性能問題?因爲它看起來像你正在做3個單獨的排序而不是1個(即使其中2個總是'null'。 – sml485

+0

@ sml485。請參閱我在附加答案中的回覆。 – BobC

+0

@ sml485 ...不,沒有額外的性能按三個鍵排序幾乎與按一個鍵排序相同 –

1

Gordon發佈的示例答案中幾乎沒有性能影響。你並不是真的在做三種不同的分類;它仍然是一個單獨的排序操作。快速測試將顯示此:

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語句

+0

您的意思是性能問題是使用'case'還是'decode'?我根據輸入使用單獨的語句。然而,我的實際表格有9列可以排序,一些相當複雜的聚合/連接集中在內部。我極大地簡化了這個問題,以突出「解碼」問題。將它們拆分爲9個單獨的查詢聽起來像維護地獄:( – sml485

+0

@ sml485。我的評論有些泛泛,但我已經看到了非常複雜的SQL語句,開發人員試圖很聰明,其構造如下所示:SELECT * FROM emp WHERE ename =:1 OR:1 IS NULL)和(job =:2 OR:2 IS NULL)。問題是優化器沒有辦法確定謂詞的選擇性,因此性能是次優的所以我只是警告使用「超級通用」的SQL語句,是的,你將有權衡維護成本;但是我也建議更簡單的SQL語句更容易調試和維護。 – BobC