【问题标题】:Oracle SELECT TOP 10 records [duplicate]Oracle SELECT TOP 10 记录 [重复]
【发布时间】:2011-01-30 16:19:46
【问题描述】:

我对 Oracle 中的 SQL 语句有一个大问题。我想选择 STORAGE_DB 排序的 TOP 10 记录,这些记录不在其他选择语句的列表中。

这个适用于所有记录:

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

【问题讨论】:

    标签: sql oracle top-n


    【解决方案1】:

    您可以使用此查询来选择 oracle 中的顶级记录。拉克什 B

    select * from User_info where id >= (select max(id)-10 from User_info);

    【讨论】:

    • 嘿拉克什!我不确定这个答案是否完全解决了提出的问题。查看其他一些响应,这些响应提供了更多详细信息,并且针对一些示例进行了良好的格式设置。
    【解决方案2】:

    试试

    SELECT * FROM users FETCH NEXT 10 ROWS ONLY;
    

    【讨论】:

      【解决方案3】:

      如果您使用的是 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

      【讨论】:

      • 与其他答案相比,这是黄金
      • 我同意 aswzen
      • 我想给这个答案100个赞!但是,唉,我只有一个可以奖励。就是一个!
      【解决方案4】:

      您得到一个明显随机的集合,因为 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
      

      【讨论】:

        【解决方案5】:

        关于性能不佳的问题可能有很多,这确实应该是一个单独的问题。然而,有一件明显的事情可能是个问题:

        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 索引的使用。

        【讨论】:

          【解决方案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 了解更多信息。

          【讨论】:

          • NOT EXISTS 在这种情况下不起作用(无效的关系运算符)APP_ID NOT EXISTS (SELEC...)
          • 有人可能会说这很容易让人们对 Oracle 失去兴趣。
          • 查看下面的FETCH NEXT N ROWS ONLY 答案。
          • @Padmarag :rownum 何时适用于这样的查询 - 从 SomeTable 中选择 *,其中 someColumn = '123' 和 rownum 中选择结果后
          • 尝试使用:select * from (select * from history order by storage_gb desc) where rownum
          猜你喜欢
          • 1970-01-01
          • 2015-11-29
          • 2011-07-21
          • 2011-08-03
          • 1970-01-01
          • 2020-03-25
          • 2020-03-13
          • 2017-03-20
          相关资源
          最近更新 更多