Oracle SELECT TOP 10 записей

У меня большая проблема с оператором 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 + записей)


person opHASnoNAME    schedule 23.03.2010    source источник
comment
Вероятный дубликат: stackoverflow.com/questions/2306744/   -  person APC    schedule 23.03.2010
comment


Ответы (6)


Вам нужно будет поместить текущий запрос в подзапрос, как показано ниже:

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. Дополнительную информацию см. В this.

person Padmarag    schedule 23.03.2010
comment
NOT EXISTS не работает в этом сценарии (недопустимый оператор отношения) APP_ID НЕ СУЩЕСТВУЕТ (SELEC ...) - person opHASnoNAME; 23.03.2010
comment
Некоторые могут сказать, что это склонно отвлекать людей от Oracle. - person MrBoJangles; 02.05.2018
comment
Проверьте FETCH NEXT N ROWS ONLY ответ ниже. - person Mohnish; 28.09.2018
comment
@Padmarag: Когда применяется rownum в запросе, подобном этому - Выберите * из SomeTable, где someColumn = '123' и rownum ‹= 3. Это после выбора результатов из [Выбрать * из SomeTable, где someColumn = '123'] - person Farhan Shirgill Ansari; 03.12.2019

Если вы используете 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

person Volpato    schedule 03.08.2016
comment
это золото по сравнению с другим ответом - person aswzen; 04.07.2018
comment
Я согласен с aswzen - person Austin Springer; 11.09.2018
comment
Я хочу дать на этот ответ 100 голосов! Но, увы, наградить мне осталось только одно. Одно это! - person eidylon; 28.06.2019

пытаться

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;
person Shaaban    schedule 22.06.2017

Что касается плохой производительности, то это может быть множество вещей, и это действительно должен быть отдельный вопрос. Однако есть одна очевидная вещь, которая может быть проблемой:

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.

person APC    schedule 23.03.2010

Вы получаете явно случайный набор, потому что 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
person vijaya    schedule 23.03.2010

вы можете использовать этот запрос для выбора самых популярных записей в oracle. Ракеш Б.

выберите * из User_info, где id ›= (выберите max (id) -10 из User_info);

person Rakesh Bollu    schedule 06.01.2021
comment
Привет, Ракеш! Я не уверен, что этот ответ полностью отвечает на поставленный вопрос. Ознакомьтесь с некоторыми другими ответами, которые содержат более подробную информацию и хорошо отформатированы для некоторых примеров. - person krfurlong; 06.01.2021