Oracle SELECT ТОП 10 записів


144

У мене є велика проблема із заявою SQL в Oracle. Я хочу вибрати ТОП -10 записів, упорядкованих STORAGE_DB, які відсутні в списку з іншого оператора вибору.

Цей відмінно підходить для всіх записів:

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

Але коли я додаю

AND ROWNUM <= 10
ORDER BY STORAGE_GB DESC

Я отримую якісь "випадкові" записи. Я думаю, тому що ліміт діє перед замовленням.

Хтось має хороше рішення? Інша проблема: Цей запит дійсно повільний (10k + записи)


Ймовірний дублікат: stackoverflow.com/questions/2306744/…
APC

Відповіді:


199

Вам потрібно буде розмістити поточний запит у підзапиті, як показано нижче:

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 застосовує rownum до результату після його повернення.
Потрібно відфільтрувати результат після його повернення, тому потрібен підзапит. Ви також можете використовувати функцію RANK () для отримання результатів Top-N.

Для продуктивності спробуйте використовувати NOT EXISTSзамість NOT IN. Дивіться це докладніше.


NOT EXISTS не працює в цьому сценарії (недійсний реляційний оператор) APP_ID NOT EXISTS (SELEC ...)
opHASnoNAME

3
Деякі можуть сказати, що це сприятливо відвертати людей до Oracle.
MrBoJangles

2
Перевірте FETCH NEXT N ROWS ONLYвідповідь нижче.
Mohnish

@Padmarag: Коли використовується rownum, застосуйте такий запит - Виберіть * з SomeTable, де someColumn = '123' та rownum <= 3. Це після вибору результатів із [Вибрати * з SomeTable, де someColumn = '123']
Ширгілл Фархан

55

Якщо ви використовуєте Oracle 12c, використовуйте:

ТОЛЬКО ВИДАЙТЕ СЛЕДУЮЩИЙ N РЯДІВ

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

Більше інформації: http://docs.oracle.com/javadb/10.5.3.0/ref/rrefsqljoffsetfetch.html


2
це золото порівняно з іншими відповідями
aswzen

Я згоден з aswzen
Остін Спрінгер

1
Я хочу дати цю відповідь 100 оновлень! Але, на жаль, у мене є лише один нагорода. Одне це!
ейдилон

23

Що стосується низької продуктивності, то це може бути чимало речей, і це справді повинно бути окремим питанням. Однак є одна очевидна річ, яка може бути проблемою:

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

Якщо HISTORY_DATE дійсно є стовпцем дати та якщо він має індекс, то це перезапис буде краще:

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

Це відбувається тому, що перетворення типу даних вимикає використання індексу B-Tree.



11

Ви отримуєте, очевидно, випадковий набір, тому що ROWNUM застосовується перед ORDER BY. Таким чином, ваш запит займає перші десять рядків і сортує їх.0 Щоб вибрати десять найвищих зарплат, слід використати аналітичну функцію в підзапиті, а потім відфільтрувати:

 select * from 
     (select empno,
             ename,
             sal,
             row_number() over(order by sal desc nulls last) rnm
    from emp) 
 where rnm<=10
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.