2017-02-10 1 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_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 

По какой-то причине, декодирование сортировки 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

В ответе на пример, опубликованном Гордоном, не будет никакого влияния на производительность. Вы действительно не делаете 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 выполнить.

+0

Вы имеете в виду проблему производительности с использованием 'case' или' decode'?Я могу использовать отдельные инструкции в зависимости от ввода. Однако моя фактическая таблица имеет 9 столбцов для сортировки, причем некоторые довольно запутанные агрегации/объединения сосредоточены внутри. Я очень упростил это для этого вопроса, чтобы выделить проблему «декодирования». Разделение их на 9 отдельных запросов звучит как обслуживание hell :( – sml485

+0

@ sml485. Мой комментарий несколько общий, но я видел очень сложные операторы SQL, в которых разработчик пытался быть умным, с конструкциями вроде: SELECT * FROM emp WHERE (ename =: 1 OR: 1 IS NULL) и (job =: 2 OR: 2 IS NULL). Проблема заключается в том, что оптимизатор не имеет способа определить избирательность предикатов, и, как следствие, производительность является неоптимальной Поэтому я просто предупреждаю об использовании «супер-общего» SQL-оператора. Да, вы будете иметь вес стоимости обслуживания, но я также предложил бы упростить отладку и поддержку более простого оператора SQL. – BobC

Смежные вопросы