选择TOP N和BOTTOM N.

时间:2017-11-21 18:51:18

标签: oracle ranking top-n

尝试获取前n行n行。虽然它给了我结果但是,它需要很多时间。我相信它扫描表两次。

Code used:
WITH TI AS
(SELECT * FROM
(SELECT
Column1,
Column2,
Colmn3
FROM TABLE
ORDER BY DESC
)
WHERE ROWNUM<=5),
T2 AS
(SELECT * FROM
(SELECT
Column1,
Column2,
Colmn3
FROM TABLE
ORDER BY ASC
)
WHERE ROWNUM<=5)

SELECT * FROM T1
UNION ALL
SELECT * FROM T2

我怎样才能更快地获取这个? 考虑到表格会定期更新。

2 个答案:

答案 0 :(得分:2)

解决此问题的最佳方法部分取决于您的Oracle版本。这是一个非常简单(我怀疑,非常有效)的解决方案,使用版本12.1中添加的match_recognize子句。

我使用标准EMPLOYEES架构中的HR表来说明它,按SALARY排序。这里唯一的技巧是选择顶部和底部五行,并忽略它们之间的所有内容;那个(“忽略”)是{- ... -}运算符在pattern子句中的作用。

select employee_id, first_name, last_name, salary
from   hr.employees
match_recognize(
  order by salary desc
  all rows per match
  pattern ( a{5} {- a* -} a{5} )
  define a as 0 = 0             -- For reasons known only to Oracle, DEFINE is required.
);

EMPLOYEE_ID FIRST_NAME           LAST_NAME                     SALARY
----------- -------------------- ------------------------- ----------
        100 Steven               King                           24000
        101 Neena                Kochhar                        17000
        102 Lex                  De Haan                        17000
        145 John                 Russell                        14000
        146 Karen                Partners                       13500
        135 Ki                   Gee                             2400
        127 James                Landry                          2400
        136 Hazel                Philtanker                      2200
        128 Steven               Markle                          2200
        132 TJ                   Olson                           2100

答案 1 :(得分:1)

您可以使用analytic functions将单个查询和单个传递合并到表中,在这种情况下生成两个伪列:

select column1, column2, column3,
  row_number() over (order by column1 desc) rn_desc,
  row_number() over (order by column1 asc) rn_asc
from your_table;

然后使用该查询过滤为内联视图(或CTE):

select column1, column2, column3
from (
  select column1, column2, column3,
    row_number() over (order by column1 desc) as rn_desc,
    row_number() over (order by column1 asc) as rn_asc
  from your_table
)
where rn_desc <=5
or rn_asc <= 5;

我假设您的订单位于column1,并选择your_table作为表名,因为您没有包含该名称,因此请根据需要进行更改。根据您想要处理关系的方式,您可能希望使用rank()dense_rank()函数。

从@ mathguy的评论来看,这可能表现得更好:

select column1, column2, column3
from (
  select column1, column2, column3,
    row_number() over (order by column1 desc) as rn,
    count(*) over () as cnt
  from your_table
)
where rn <=5
or cnt - rn < 5;