何时选择rank而不是density_rank或row_number

问题描述

由于我们可以使用row_number()获得分配的行号,并且如果我们想使用dense_rank()在不跳过分区内任何数字的情况下查找每一行的行列,为什么我们需要{{ 1}}函数,我想不出rank()函数提供的任何用例是rank()dense_rank()都无法实现的。

是否有最适合row_number()的用例?

解决方法

RANKDENSE_RANK应用于没有关系的列时,它们都将导致由ROW_NUMBER生成的同一序列。 RANKDENSE_RANK之间的区别出现在存在联系的情况下,并且微妙。考虑下表以及行号,等级和密集等级值:

SALARY | ROW_NUMBER | RANK | DENSE_RANK
1000   | 1          | 1    | 1
1500   | 2          | 2    | 2
1500   | 3          | 2    | 2
2000   | 4          | 4    | 3
2200   | 5          | 5    | 4
2500   | 6          | 6    | 5
2500   | 7          | 6    | 5
2500   | 8          | 6    | 5
3000   | 9          | 9    | 6

希望您可以在上方看到,当出现两个或多个记录的并列时,RANKDENSE_RANK会为所有具有相同值的记录分配相同的等级。但是,它们的不同之处在于,RANK继续按照ROW_NUMBER系列进行等级计数,而DENSE_RANK则没有,而是使用重复等级之后的下一个值继续进行等级计数

现在开始提问,选择RANK还是DENSE_RANK取决于您的要求。例如,如果您要报告获胜者,并且始终需要报告第一,第二和第三名,而与每个地方的关系无关,则可以使用DENSE_RANK。否则,您将使用RANK,这可能意味着没有第二或第三位。如果您确定永远不会重复,则可以使用ROW_NUMBER

,

以下示例应有助于说明差异。 (下面示例的数据库小提琴链接-https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=cef0a4da7559de657aae332491a9c500

CREATE TABLE t AS
SELECT 'p' v FROM dual UNION ALL
SELECT 'p'   FROM dual UNION ALL
SELECT 'p'   FROM dual UNION ALL
SELECT 'q'   FROM dual UNION ALL
SELECT 'r'   FROM dual UNION ALL
SELECT 'r'   FROM dual UNION ALL
SELECT 's'   FROM dual UNION ALL
SELECT 't'   FROM dual;

SELECT
  v,ROW_NUMBER() OVER (ORDER BY v) row_number,RANK()       OVER (ORDER BY v) rank,DENSE_RANK() OVER (ORDER BY v) dense_rank
FROM t
ORDER BY v;
The above will yield:

+---+------------+------+------------+
| V | ROW_NUMBER | RANK | DENSE_RANK |
+---+------------+------+------------+
| p |          1 |    1 |          1 |
| p |          2 |    1 |          1 |
| p |          3 |    1 |          1 |
| q |          4 |    4 |          2 |
| r |          5 |    5 |          3 |
| r |          6 |    5 |          3 |
| s |          7 |    7 |          4 |
| t |          8 |    8 |          5 |
+---+------------+------+------------+

领带被分配给RANK和DENSE_RANK相同的等级,但是在领带之后的RANK中,您将获得等级,跳过下一个排名。用粗体标记的最后一部分是RANK和DENSE_RANK之间的唯一区别。在DENSE_RANK中,不会跳过数字。

可以想象一个很好的类比,您的班级中最高的总成绩是由2位学生获得的。因此,第一个位置并列。您必须给他们两个都得一等奖。现在,您的学生的总成绩仅次于最高分,您将其分配给哪个职位。如果您询问RANK()函数-它会告诉您第三,因为第一位置被2个人占用。但是,如果您要求DENSE_RANK()函数-它会告诉您第二个位置,因为它不会跳过任何排名,因此在这种情况下,第三个位置将被授予总体得分仅次于第二个位置的其他人。虽然如果您的问题是您仅获得第一名的奖金只有一名获胜者:-),那么ROW_NUMBER将为您解决,因为ROW_NUMNER()会随机分配第一和第二名给那些得了最高分(有点像彩票),因此在这种情况下,第3位没有矛盾。

现在进入RANK用例:我知道一个事实,很多预选赛考试都使用RANK()方法(不一定是数据库中的等级函数,而是相同的算法或方法)选拔学生人数,因为有时比赛可能非常接近,所以联系并不是那么罕见。但是,问题是-有一定的级别,例如50个级别,但同时它们具有固定数量的席位,不能超过。因此,在并列的情况下,您必须向两个学生授予相同的等级,因为如果两个人得分都相同,那么您将无能为力,但是下一等级将被跳过,否则席位将被超满。这类似于说一个足球联赛,在联赛结束时,您有多个得分相同的球队。现在在这种联赛中,您可以使用其他标准(例如进球数等)来消除季后赛的并列,但是在进行检查的情况下,您当然不能通过重新检查来消除并列。这是一个非常实用的用例,用于说明该概念有时在哪些方面有用。