2017-02-10 1 views
2

Ich habe eine Tabelle von Flugdaten wie folgt erstelltSQL ORDER BY DECODE sortiert die Nummer als String?

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

ich dann eine Funktion haben, die meine Anwendung ruft die Datensätze nach der ausgewählten Spalte (in absteigender Reihenfolge) sortiert abzurufen.

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; 

sowohl Sortierung nach FLIGHT_NO und DEPARTURE_DTE korrekt funktioniert. Mein Problem kommt, wenn ich von TOTAL_PASSENGERS zu sortieren versucht, die hat mich dieses

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 

Aus irgendeinem Grund wird DECODE die NUMBER Spalte als String sortieren. Um zu testen, habe ich versucht, diesen

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

, die mir gegeben hat

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 

beweisen, dass das Problem nicht mit der Säule selbst.

Dann habe ich versucht, einige Lösungen, die ich auf 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; 

von denen keine (es ist nach wie vor als String sortiert) arbeitete gefunden.

Warum also weigert sich DECODE, eine Zahlenspalte als Zahl zu sortieren? Und wie bekomme ich es richtig zu sortieren?

Antwort

2

Ihr Problem ist, dass decode() ein Ausdruck ist und nur einen Typ zurückgibt. Also müssen die Typen konvertiert werden.

sollten Sie case trotzdem verwenden. Meine bevorzugte Methode ist mehrere Anweisungen:

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; 

Jeder Ausdruck sortiert nach einem Schlüssel. Wenn der Sortierschlüssel nicht übereinstimmt, lautet das Ergebnis des Ausdrucks NULL - alle Zeilen erhalten den gleichen Wert, sodass sie die Reihenfolge nicht beeinflussen.

+0

Das sieht gut aus! Wird es keinen Performance-Hit geben? Da sieht es so aus, als würden Sie 3 separate Sortierungen anstelle von 1 durchführen (auch wenn 2 immer "null" sind. – sml485

+0

@ sml485. Siehe meine Antwort in der zusätzlichen Antwort. – BobC

+0

@ sml485.. Nein, es gibt keine zusätzliche Leistung Die Sortierung nach drei Tasten entspricht ungefähr der Sortierung nach einer Taste –

1

In der Beispielantwort von Gordon wird es wenig bis keine Leistungseinbußen geben. Du machst nicht wirklich 3 verschiedene Sorten; es ist immer noch eine einzige Sortieroperation. Ein schneller Test zeigt dies:

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

Jedoch habe ich einen Ansatz warnen würde, wo Sie versuchen, eine einzelne „generic“ SQL-Anweisung zu schreiben, alle Arten von verschiedenen Fälle zu behandeln. Während diese Art von "cleveren" SQL-Anweisungen funktional funktionieren kann, kann es für die Performance ein Desaster sein. Es ist viel besser, separate SQL-Anweisungen zu haben. In diesem hier veröffentlichten Beispiel wäre es ziemlich einfach, drei verschiedene SQL-Anweisungen mit jeweils einer spezifischen ORDER BY-Klausel zu haben und dann einen einfachen IF THEN ELSE für den Eingabeparameter zu verwenden, um zu bestimmen, welche SQL-Anweisung ausgeführt werden soll:

+0

Meinst du, das Leistungsproblem kommt mit 'case' oder' decode'?Ich benutze separate Anweisungen je nach Eingabe. Allerdings hat meine tatsächliche Tabelle 9 Spalten, nach denen sortiert wird, mit einigen ziemlich verworrenen Aggregation/Joins, die im Inneren zusammengefasst sind. Ich habe es für diese Frage stark vereinfacht, um das 'Decodierung'-Problem hervorzuheben. sie in 9 separate Abfragen Splitting klingt wie Wartung Hölle :( – sml485

+0

@ sml485 Mein Kommentar etwas allgemeines Aber ich habe sehr komplexe SQL-Anweisungen zu sehen, wo der Entwickler versucht hat, klug zu sein, mit Konstrukten wie:.. SELECT FROM emp * WHERE (ename =: 1 OR: 1 IS NULL) und (job =: 2 OR: 2 IS NULL) Das Problem ist, dass der Optimierer keine Möglichkeit hat, die Selektivität der Prädikate zu bestimmen, und als Konsequenz ist die Leistung nicht optimal Daher warne ich nur die Verwendung der "super generischen" SQL-Anweisung. Ja, Sie werden die Wartungskosten abwägen, aber ich würde auch vorschlagen, dass eine einfachere SQL-Anweisung leichter zu debuggen und zu warten ist. – BobC