oracle – 在没有ROWNUM的情况下选择前N行?

前端之家收集整理的这篇文章主要介绍了oracle – 在没有ROWNUM的情况下选择前N行?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我希望你能帮我做作业:)

我们需要构建一个输出前N名最佳薪酬员工的查询.

我的版本完美无缺.
例如前三名:

  1. SELECT name,salary
  2. FROM staff
  3. WHERE salary IN ( SELECT *
  4. FROM ( SELECT salary
  5. FROM staff
  6. ORDER BY salary DESC )
  7. WHERE ROWNUM <= 3 )
  8. ORDER BY salary DESC
  9. ;

请注意,这将输出位于前3名且薪水相同的员工.

1: Mike,4080
2: Steve,2800
2: Susan,2800
2: Jack,2800
3: Chloe,1400

但现在我们的老师不允许我们使用ROWNUM.
搜索得很远,没有找到任何可用的东西.

贾斯汀洞穴的暗示,这是我的第二个解决方案.

首先我试过这个:

  1. SELECT name,salary,( rank() OVER ( ORDER BY salary DESC ) ) as myorder
  2. FROM staff
  3. WHERE myorder <= 3
  4. ;

错误消息是:“myorder:invalid identifier”

感谢DCookie,现在很清楚:

“[…] Analytics are applied AFTER
the where clause is evaluated,which
is why you get the error that myorder
is an invalid identifier.”

包装SELECT解决了这个问题:

  1. SELECT *
  2. FROM ( SELECT name,rank() OVER ( ORDER BY salary DESC ) as myorder FROM staff )
  3. WHERE myorder <= 3
  4. ;

我的老师再次罢工,不允许这种奇特的分析功能.

来自@Justin Caves的第三个解决方案.

“If analytic functions are also
disallowed,the other option I could
imagine– one that you would never,
ever,ever actually write in practice,
would be something like”

  1. SELECT name,salary
  2. FROM staff s1
  3. WHERE (SELECT COUNT(*)
  4. FROM staff s2
  5. WHERE s1.salary < s2.salary) <= 3
因为这是作业,提示而不是答案.您将需要使用分析函数. ROW_NUMBER,RANK或DENSE_RANK可以根据您想要处理关系的方式工作.

如果也不允许分析函数,我可以想象的另一个选项 – 你永远不会,实际上在实践中写的那个,就像是

  1. SELECT name,salary
  2. FROM staff s1
  3. WHERE (SELECT COUNT(*)
  4. FROM staff s2
  5. WHERE s1.salary < s2.salary) <= 3

关于性能,我不会依赖查询计划中的COST编号 – 这只是一个估计,通常不可能比较不同sql语句的计划之间的成本.你可以更好地查看查询实际执行的一致获取次数,并考虑查询性能随着表中行数的增加而缩放的情况.第三个选项的效率远远低于其他两个选项,因为它需要两次扫描STAFF表.

我没有你的STAFF表,所以我将使用SCOTT模式中的EMP表

分析函数解决方案实际上与ROWNUM解决方案一样进行7次一致性获取

  1. Wrote file afiedt.buf
  2.  
  3. 1 select ename,sal
  4. 2 from( select ename,3 sal,4 rank() over (order by sal) rnk
  5. 5 from emp )
  6. 6* where rnk <= 3
  7. sql> /
  8.  
  9. ENAME SAL
  10. ---------- ----------
  11. smith 800
  12. SM0 950
  13. ADAMS 1110
  14.  
  15.  
  16. Execution Plan
  17. ----------------------------------------------------------
  18. Plan hash value: 3291446077
  19.  
  20. --------------------------------------------------------------------------------
  21. -
  22. | Id | Operation | Name | Rows | Bytes | Cost (%cpu)| Time
  23. |
  24. --------------------------------------------------------------------------------
  25. -
  26. | 0 | SELECT STATEMENT | | 14 | 672 | 4 (25)| 00:00:01
  27. |* 1 | VIEW | | 14 | 672 | 4 (25)| 00:00:01
  28. |* 2 | WINDOW SORT PUSHED RANK| | 14 | 140 | 4 (25)| 00:00:01
  29. | 3 | TABLE ACCESS FULL | EMP | 14 | 140 | 3 (0)| 00:00:01
  30. --------------------------------------------------------------------------------
  31. -
  32.  
  33. Predicate Information (identified by operation id):
  34. ---------------------------------------------------
  35.  
  36. 1 - filter("RNK"<=3)
  37. 2 - filter(RANK() OVER ( ORDER BY "SAL")<=3)
  38.  
  39.  
  40. Statistics
  41. ----------------------------------------------------------
  42. 0 recursive calls
  43. 0 db block gets
  44. 7 consistent gets
  45. 0 physical reads
  46. 0 redo size
  47. 668 bytes sent via sql*Net to client
  48. 524 bytes received via sql*Net from client
  49. 2 sql*Net roundtrips to/from client
  50. 1 sorts (memory)
  51. 0 sorts (disk)
  52. 3 rows processed
  53.  
  54. sql> select ename,sal
  55. 3 from emp
  56. 4 order by sal )
  57. 5 where rownum <= 3;
  58.  
  59. ENAME SAL
  60. ---------- ----------
  61. smith 800
  62. SM0 950
  63. ADAMS 1110
  64.  
  65.  
  66. Execution Plan
  67. ----------------------------------------------------------
  68. Plan hash value: 1744961472
  69.  
  70. --------------------------------------------------------------------------------
  71. | Id | Operation | Name | Rows | Bytes | Cost (%cpu)| Time |
  72. --------------------------------------------------------------------------------
  73. | 0 | SELECT STATEMENT | | 3 | 105 | 4 (25)| 00:00:01 |
  74. |* 1 | COUNT STOPKEY | | | | | |
  75. | 2 | VIEW | | 14 | 490 | 4 (25)| 00:00:01 |
  76. |* 3 | SORT ORDER BY STOPKEY| | 14 | 140 | 4 (25)| 00:00:01 |
  77. | 4 | TABLE ACCESS FULL | EMP | 14 | 140 | 3 (0)| 00:00:01 |
  78. --------------------------------------------------------------------------------
  79.  
  80.  
  81. Predicate Information (identified by operation id):
  82. ---------------------------------------------------
  83.  
  84. 1 - filter(ROWNUM<=3)
  85. 3 - filter(ROWNUM<=3)
  86.  
  87.  
  88. Statistics
  89. ----------------------------------------------------------
  90. 1 recursive calls
  91. 0 db block gets
  92. 7 consistent gets
  93. 0 physical reads
  94. 0 redo size
  95. 668 bytes sent via sql*Net to client
  96. 524 bytes received via sql*Net from client
  97. 2 sql*Net roundtrips to/from client
  98. 1 sorts (memory)
  99. 0 sorts (disk)
  100. 3 rows processed

但是,COUNT(*)解决方案实际上会执行99次一致性获取,并且必须对表进行两次完整扫描,因此效率低10倍以上.随着表中行数的增加,它的扩展性会更差

  1. sql> select ename,sal
  2. 2 from emp e1
  3. 3 where (select count(*) from emp e2 where e1.sal < e2.sal) <= 3;
  4.  
  5. ENAME SAL
  6. ---------- ----------
  7. JONES 2975
  8. SCOTT 3000
  9. KING 5000
  10. FORD 3000
  11. FOO
  12.  
  13.  
  14. Execution Plan
  15. ----------------------------------------------------------
  16. Plan hash value: 2649664444
  17.  
  18. ----------------------------------------------------------------------------
  19. | Id | Operation | Name | Rows | Bytes | Cost (%cpu)| Time |
  20. ----------------------------------------------------------------------------
  21. | 0 | SELECT STATEMENT | | 14 | 140 | 24 (0)| 00:00:01 |
  22. |* 1 | FILTER | | | | | |
  23. | 2 | TABLE ACCESS FULL | EMP | 14 | 140 | 3 (0)| 00:00:01 |
  24. | 3 | SORT AGGREGATE | | 1 | 4 | | |
  25. |* 4 | TABLE ACCESS FULL| EMP | 1 | 4 | 3 (0)| 00:00:01 |
  26. ----------------------------------------------------------------------------
  27.  
  28. Predicate Information (identified by operation id):
  29. ---------------------------------------------------
  30.  
  31. 1 - filter( (SELECT COUNT(*) FROM "EMP" "E2" WHERE
  32. "E2"."SAL">:B1)<=3)
  33. 4 - filter("E2"."SAL">:B1)
  34.  
  35.  
  36. Statistics
  37. ----------------------------------------------------------
  38. 0 recursive calls
  39. 0 db block gets
  40. 99 consistent gets
  41. 0 physical reads
  42. 0 redo size
  43. 691 bytes sent via sql*Net to client
  44. 524 bytes received via sql*Net from client
  45. 2 sql*Net roundtrips to/from client
  46. 0 sorts (memory)
  47. 0 sorts (disk)
  48. 5 rows processed

猜你在找的Oracle相关文章