Oracle SELECT TOP 10记录


144

我在Oracle中使用SQL语句遇到了很大的问题。我想选择STORAGE_DB排序的前10条记录,这些记录不在其他select语句的列表中。

此记录适用于所有记录:

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条记录)



Answers:


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()函数来获取前N个结果。

为了提高性能,请尝试使用NOT EXISTS代替NOT IN。见更多。


NOT EXISTS在这种情况下不起作用(无效的关系运算符)APP_ID NOT EXISTS(SELEC ...)
opHASnoNAME

3
有人可能会说这很容易使人们不愿使用Oracle。
MrBoJangles

2
检查FETCH NEXT N ROWS ONLY下面的答案。
Mohnish

@Padmarag:何时将行号应用于像这样的查询中-从SomeTable中选择*,其中someColumn ='123'并且rownum <= 3。是从[Select * from SomeTable where someColumn ='123']中选择结果之后
Shirgill Farhan

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

1
我想给这个答案100个投票!但是,a,我只有一个奖。一是!
eidylon

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树索引。


22

尝试

SELECT * FROM users FETCH NEXT 10 ROWS ONLY;

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.