2010-03-23 9 views
85

Mam duży problem z SQL Statement w Oracle. Chcę wybrać TOP 10 rekordów uporządkowanych przez STORAGE_DB, które nie znajdują się na liście od innej instrukcji select.Oracle SELECT rekord 10 najlepszych

Ten działa dobrze dla wszystkich rekordów:

SELECT DISTINCT 
    APP_ID, 
    NAME, 
    STORAGE_GB, 
    HISTORY_CREATED, 
    TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE 
    FROM HISTORY WHERE 
     STORAGE_GB IS NOT NULL AND 
     APP_ID NOT IN (SELECT APP_ID 
         FROM HISTORY 
         WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Ale gdy dodaję

AND ROWNUM <= 10 
ORDER BY STORAGE_GB DESC 

Dostaję jakieś "losowych" Records. Myślę, że ponieważ limit obowiązuje przed zamówieniem.

Czy ktoś ma dobre rozwiązanie? Inny problem: To zapytanie jest naprawdę powolne (10k + rekordy)

+0

Prawdopodobny duplikat: http://stackoverflow.com/questions/2306744/oracle-sql-how-to-retrieve-highest-5-values-of-a-column – APC

Odpowiedz

142

Musisz umieścić swoją aktualną kwerendę w podzapytaniu jak poniżej:

SELECT * FROM (
    SELECT DISTINCT 
    APP_ID, 
    NAME, 
    STORAGE_GB, 
    HISTORY_CREATED, 
    TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE 
    FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
     APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009') 
    ORDER BY STORAGE_GB DESC) 
WHERE ROWNUM <= 10 

Oracle stosuje rownum do wyniku po to został zwrócony.
Należy odfiltrować wynik po jego zwróceniu, więc wymagane jest podkwerendy. Możesz także użyć funkcji RANK(), aby uzyskać wyniki Top-N.
Dla uzyskania wydajności spróbuj użyć NOT EXISTS zamiast NOT IN. Aby uzyskać więcej informacji, patrz this.

+0

NOT EXISTS nie działa w tym scenariuszu (nieprawidłowy operator relacyjny) APP_ID NOT EXISTS (SELEC ...) – opHASnoNAME

22

Jeśli chodzi o słabe wyniki, istnieje wiele rzeczy, które mogą być, i to naprawdę powinno być oddzielne pytanie. Jednak jest jedna rzeczą oczywistą, że może być problem:

WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') = '06.02.2009') 

Jeśli HISTORY_DATE naprawdę jest kolumna data i jeśli to ma indeks wówczas przepisanie wykona lepiej:

WHERE HISTORY_DATE = TO_DATE ('06.02.2009', 'DD.MM.YYYY') 

To dlatego, konwersja typu danych wyłącza użycie indeksu B-Tree.

10

Otrzymujesz zestaw pozornie losowy, ponieważ ROWNUM jest stosowany przed ORDER BY. Tak więc zapytanie wykonuje pierwsze dziesięć wierszy i je sortuje.0 Aby wybrać w pierwszej dziesiątce wynagrodzenia należy użyć funkcji analitycznej w podzapytania, a następnie filtrować że:

select * from 
    (select empno, 
      ename, 
      sal, 
      row_number() over(order by sal desc nulls last) rnm 
    from emp) 
where rnm<=10 
11

Jeśli używasz Oracle 12c, można użyć:

sprowadzić kolejne tylko n wierszy

SELECT DISTINCT 
    APP_ID, 
    NAME, 
    STORAGE_GB, 
    HISTORY_CREATED, 
    TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') AS HISTORY_DATE 
    FROM HISTORY WHERE 
    STORAGE_GB IS NOT NULL AND 
     APP_ID NOT IN (SELECT APP_ID FROM HISTORY WHERE TO_CHAR(HISTORY_DATE, 'DD.MM.YYYY') ='06.02.2009') 
    ORDER BY STORAGE_GB DESC 
FETCH NEXT 10 ROWS ONLY 

Więcej informacji: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html

+1

Proste i na temat. NASTĘPNE 10 TYLKO 10 WIERSZY –

-4

można po prostu użyj TOP Clause

SELECT TOP 10 * Z TABLE;

lub

SELECT nazwa_kolumny (e) Z table_name GDZIE ROWNUM < = liczba;

+1

Nie w Oracle Oracle ... – Zafi

2

spróbuj WYBIERZ * OD użytkowników POTWIERDŹ NA 10 TYLKO RZĘD;

+0

Działa tylko w Oracle 12c i nowszych – Volpato

Powiązane problemy