oracle中rownum的奥秘

2021-12-30 00:00:00 oracle11g oracle

我正在努力根据 rownum 获取数据.当我执行以下查询以获取基于 rownum 1 到 4 的结果时,它工作正常.

I am struggling to fetch the data based on rownum. When I execute the below query to get the results based rownum 1 to 4 then it is working fine.

  SELECT ROWNUM TOTAL,MI.* FROM (SELECT USER_ID,CUSTOMER_NAME FROM ELEC_AUTO_MERC 
  ORDER BY CREATION_DATE DESC ) MI WHERE ROWNUM BETWEEN 1 AND 4;

但是当我执行相同的查询以从 rownum 2 to 4 获取结果时,它不起作用,它不返回任何内容.

But when I am executing same query to get result from rownum 2 to 4 then it is not working, it doesn't return anything.

  SELECT ROWNUM TOTAL,MI.* FROM (SELECT USER_ID,CUSTOMER_NAME FROM ELEC_AUTO_MERC 
  ORDER BY CREATION_DATE DESC ) MI WHERE ROWNUM BETWEEN 2 AND 4;

作为一种解决方法,当我再使用一个 SELECT 语句时它工作正常,但我认为仅对 rownum 多次使用 SELECT 不是好方法.

As a workaround, when I use one more SELECT statement then it is working fine, but I don't think it is good approach to use SELECT multiple times only for rownum.

SELECT * FROM (SELECT ROWNUM TOTAL,MI.* FROM (SELECT USER_ID,CUSTOMER_NAME FROM ELEC_AUTO_MERC 
  ORDER BY CREATION_DATE DESC ) MI) WHERE TOTAL BETWEEN 2 AND 4;

你能帮我创建优化查询吗?

Can you please help me out to create optimize query?

推荐答案

ROWNUM 很奇怪,因为它可以作为查询条件的一部分进行评估 - 但如果该行未能通过该过滤器,分配给它的 ROWNUM 值可以再次用于下一行.

ROWNUM is weird in that it can be evaluated as part of a condition in the query - but if the row then fails to pass that filter, the ROWNUM value that it was assigned becomes available to be used again for the next row.

这样做的一个重要影响是,如果您使用任何排除 ROWNUM 值为 1 的条件,您将永远不会得到匹配项.针对此条件进行测试的第一行将是第 1 行;但随后它将无法通过测试,因此下一行将被视为第 1 行;等等.

One important effect of this is that if you use any condition that excludes a ROWNUM value of 1, you will never get a match. The first row to be tested against this condition will be row 1; but then it will fail the test, so the next row will then be considered row 1; and so on.

所以你的条件 ROWNUM BETWEEN 2 AND 4 永远不可能为真.

So your condition ROWNUM BETWEEN 2 AND 4 can never be true.

您找到的解决方法是传统方法.另一种方法是使用分析函数对行进行排名,然后对排名进行过滤,例如:

The workaround you have found is the traditional one. Another would be to use an analytic function to rank the rows, then filter on the rank, e.g.:

SELECT MI.* FROM (
  SELECT USER_ID,CUSTOMER_NAME, RANK() OVER (ORDER BY CREATION_DATE DESC) AS the_rank
  FROM ELEC_AUTO_MERC 
  ) MI
WHERE the_rank BETWEEN 2 AND 4;

几个分析函数 - RANK、DENSE_RANK 和 ROW_NUMBER - 可用于此目的,并且会产生略有不同的结果,尤其是在有平局的情况下.查看文档.

Several analytic functions - RANK, DENSE_RANK, and ROW_NUMBER - can be used for this purpose, and will produce slightly different results, especially if there are ties. Check out the docs.

相关文章