【问题标题】:What's the difference between RANK() and DENSE_RANK() functions in oracle?oracle 中的 RANK() 和 DENSE_RANK() 函数有什么区别?
【发布时间】:2012-06-26 08:50:25
【问题描述】:

RANK()DENSE_RANK() 函数有什么区别?如何在下面的emptbl表中找到第n个薪水?

DEPTNO  EMPNAME    SAL
------------------------------
10       rrr    10000.00
11       nnn    20000.00
11       mmm    5000.00
12       kkk    30000.00
10       fff    40000.00
10       ddd    40000.00
10       bbb    50000.00
10       ccc    50000.00

如果表数据中有nulls,如果我想找出nthsalary会怎样?

【问题讨论】:

    标签: sql oracle window-functions


    【解决方案1】:
    select empno
           ,salary
           ,row_number() over(order by salary desc) as Serial
           ,Rank() over(order by salary desc) as rank
           ,dense_rank() over(order by salary desc) as denseRank
    from emp ;
    

    Row_number() -> 用于生成序列号

    Dense_rank() 将给出连续排名,但Rank() 将在排名冲突的情况下跳过排名。

    【讨论】:

      【解决方案2】:

      RANK() 和 DENSE_RANK() 函数之间的唯一区别在于存在“平局”的情况;即,在一组中的多个值具有相同排名的情况下。在这种情况下,RANK() 将为集合中的值分配不连续的“排名”(导致出现平局时整数排名值之间的差距),而 DENSE_RANK() 将为集合中的值分配连续的排名设置(因此在平局的情况下整数排名值之间不会有差距)。

      例如,考虑集合 {30, 30, 50, 75, 75, 100}。对于这样的集合,RANK() 将返回 {1, 1, 3, 4, 4, 6}(注意值 2 和 5 被跳过),而 DENSE_RANK() 将返回 {1,1,2,3, 3,4}。

      【讨论】:

        【解决方案3】:

        Rank(), Dense_rank(), row_number() 这些都是窗口函数,这意味着它们首先充当一些有序输入集的窗口。这些窗口根据要求附加了不同的功能。以上是3:

        row_number()

        row_number() 开始,因为这构成了这些相关窗口函数的基础。顾名思义,row_number() 为应用它的行集提供了一个唯一编号。类似于给每一行一个序列号。

        Rank()

        row_number()的颠覆可以说是rank()。 Rank() 用于为那些重复的有序集合行提供相同的序列号,但它仍然保持计数类似于row_number() 对于所有那些重复 rank() 之后的含义,如下所示。对于数据 2 row_number() =rank() 意味着两者只是在重复的形式上有所不同。

        Data row_number() rank() dense_rank() 
            1         1                    1       1
            1         2                    1       1
            1         3                    1       1
            2         4                    4       2
        

        最后,

        Dense_rank() 是 rank() 的扩展版本,顾名思义,它是密集的,因为从上面的示例中可以看出,所有数据 1 的 rank() = dense_rank() 但只是数据 2 的不同之处在于形式它保持 rank() 的顺序来自先前的 rank() 而不是实际数据

        【讨论】:

          【解决方案4】:

          Rank 和 Dense rank 给出分区数据集中的排名。

          Rank() :它不会给你连续的整数。

          Dense_rank() :它给你连续的整数。

          在上图中,10008 zip的排名是dense_rank()函数为2,rank()函数为24,因为它考虑了row_number。

          【讨论】:

            【解决方案5】:

            Rank() SQL 函数在有序值集中生成数据的排名,但前一个排名之后的下一个排名是该特定行的 row_number。另一方面,Dense_Rank() SQL 函数生成下一个数字而不是生成 row_number。以下是阐明概念的 SQL 示例:

            Select ROW_NUMBER() over (order by Salary) as RowNum, Salary, 
            RANK() over (order by Salary) as Rnk, 
            DENSE_RANK() over (order by Salary) as DenseRnk from (
            Select 1000 as Salary union all
            Select 1000 as Salary union all
            Select 1000 as Salary union all
            Select 2000 as Salary union all
            Select 3000 as Salary union all
            Select 3000 as Salary union all
            Select 8000 as Salary union all
            Select 9000 as Salary) A
            

            它将生成以下输出:

            ----------------------------
            RowNum  Salary  Rnk DenseRnk
            ----------------------------
            1       1000    1   1
            2       1000    1   1
            3       1000    1   1
            4       2000    4   2
            5       3000    5   3
            6       3000    5   3
            7       8000    7   4
            8       9000    8   5
            

            【讨论】:

              【解决方案6】:

              rank() :用于对一组行中的记录进行排名。

              dense_rank():DENSE_RANK 函数的作用类似于 RANK 函数,只是它分配连续的等级。

              查询-

              select 
                  ENAME,SAL,RANK() over (order by SAL) RANK
              from 
                  EMP;
              

              输出 -

              +--------+------+------+
              | ENAME  | SAL  | RANK |
              +--------+------+------+
              | SMITH  |  800 |    1 |
              | JAMES  |  950 |    2 |
              | ADAMS  | 1100 |    3 |
              | MARTIN | 1250 |    4 |
              | WARD   | 1250 |    4 |
              | TURNER | 1500 |    6 |
              +--------+------+------+
              

              查询 -

              select 
                  ENAME,SAL,dense_rank() over (order by SAL) DEN_RANK
              from 
                  EMP;
              

              输出 -

              +--------+------+-----------+
              | ENAME  | SAL  |  DEN_RANK |
              +--------+------+-----------+
              | SMITH  |  800 |         1 |
              | JAMES  |  950 |         2 |
              | ADAMS  | 1100 |         3 |
              | MARTIN | 1250 |         4 |
              | WARD   | 1250 |         4 |
              | TURNER | 1500 |         5 |
              +--------+------+-----------+
              

              【讨论】:

                【解决方案7】:

                RANK() 和 DENSE_RANK() 函数之间的唯一区别在于存在“平局”的情况;即,在一组中的多个值具有相同排名的情况下。在这种情况下,RANK() 将为集合中的值分配不连续的“排名”(导致出现平局时整数排名值之间的差距),而 DENSE_RANK() 将为集合中的值分配连续的排名设置(因此在平局的情况下整数排名值之间不会有差距)。

                例如,考虑集合 {25, 25, 50, 75, 75, 100}。对于这样的集合,RANK() 将返回 {1, 1, 3, 4, 4, 6}(注意值 2 和 5 被跳过),而 DENSE_RANK() 将返回 {1,1,2,3, 3,4}。

                【讨论】:

                  【解决方案8】:

                  This article here nicely explains it.本质上可以这样看:

                  CREATE TABLE t AS
                  SELECT 'a' v FROM dual UNION ALL
                  SELECT 'a'   FROM dual UNION ALL
                  SELECT 'a'   FROM dual UNION ALL
                  SELECT 'b'   FROM dual UNION ALL
                  SELECT 'c'   FROM dual UNION ALL
                  SELECT 'c'   FROM dual UNION ALL
                  SELECT 'd'   FROM dual UNION ALL
                  SELECT 'e'   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;
                  

                  以上将产生:

                  +---+------------+------+------------+
                  | V | ROW_NUMBER | RANK | DENSE_RANK |
                  +---+------------+------+------------+
                  | a |          1 |    1 |          1 |
                  | a |          2 |    1 |          1 |
                  | a |          3 |    1 |          1 |
                  | b |          4 |    4 |          2 |
                  | c |          5 |    5 |          3 |
                  | c |          6 |    5 |          3 |
                  | d |          7 |    7 |          4 |
                  | e |          8 |    8 |          5 |
                  +---+------------+------+------------+
                  

                  言辞

                  • ROW_NUMBER() 为每一行赋予一个唯一值
                  • RANK() 将相同的行号赋予相同的值,留下“漏洞”
                  • DENSE_RANK() 将相同的行号赋予相同的值,不会留下任何“漏洞”

                  【讨论】:

                  • 错误:SQL 错误:ORA-00923:FROM 关键字未在预期位置找到
                  【解决方案9】:
                  SELECT empno,
                         deptno,
                         sal,
                         RANK() OVER (PARTITION BY deptno ORDER BY sal) "rank"
                  FROM   emp;
                  
                       EMPNO     DEPTNO        SAL       rank
                  ---------- ---------- ---------- ----------
                        7934         10       1300          1
                        7782         10       2450          2
                        7839         10       5000          3
                        7369         20        800          1
                        7876         20       1100          2
                        7566         20       2975          3
                        7788         20       3000          4
                        7902         20       3000          4
                        7900         30        950          1
                        7654         30       1250          2
                        7521         30       1250          2
                        7844         30       1500          4
                        7499         30       1600          5
                        7698         30       2850          6
                  
                  
                  SELECT empno,
                         deptno,
                         sal,
                         DENSE_RANK() OVER (PARTITION BY deptno ORDER BY sal) "rank"
                  FROM   emp;
                  
                       EMPNO     DEPTNO        SAL       rank
                  ---------- ---------- ---------- ----------
                        7934         10       1300          1
                        7782         10       2450          2
                        7839         10       5000          3
                        7369         20        800          1
                        7876         20       1100          2
                        7566         20       2975          3
                        7788         20       3000          4
                        7902         20       3000          4
                        7900         30        950          1
                        7654         30       1250          2
                        7521         30       1250          2
                        7844         30       1500          3
                        7499         30       1600          4
                        7698         30       2850          5
                  

                  【讨论】:

                    【解决方案10】:

                    RANK 为您提供有序分区内的排名。平局被分配相同的排名,下一个排名被跳过。因此,如果您有 3 件物品位于 2 级,则列出的下一个等级将是 5 级。

                    DENSE_RANK 再次为您提供有序分区内的排名,但排名是连续的。如果有多个项目的排名,则不会跳过排名。

                    对于空值,它取决于 ORDER BY 子句。这是一个简单的测试脚本,您可以使用它来看看会发生什么:

                    with q as (
                    select 10 deptno, 'rrr' empname, 10000.00 sal from dual union all
                    select 11, 'nnn', 20000.00 from dual union all
                    select 11, 'mmm', 5000.00 from dual union all
                    select 12, 'kkk', 30000 from dual union all
                    select 10, 'fff', 40000 from dual union all
                    select 10, 'ddd', 40000 from dual union all
                    select 10, 'bbb', 50000 from dual union all
                    select 10, 'xxx', null from dual union all
                    select 10, 'ccc', 50000 from dual)
                    select empname, deptno, sal
                         , rank() over (partition by deptno order by sal nulls first) r
                         , dense_rank() over (partition by deptno order by sal nulls first) dr1
                         , dense_rank() over (partition by deptno order by sal nulls last) dr2
                     from q; 
                    
                    EMP     DEPTNO        SAL          R        DR1        DR2
                    --- ---------- ---------- ---------- ---------- ----------
                    xxx         10                     1          1          4
                    rrr         10      10000          2          2          1
                    fff         10      40000          3          3          2
                    ddd         10      40000          3          3          2
                    ccc         10      50000          5          4          3
                    bbb         10      50000          5          4          3
                    mmm         11       5000          1          1          1
                    nnn         11      20000          2          2          2
                    kkk         12      30000          1          1          1
                    
                    9 rows selected.
                    

                    Here's a link 给一个很好的解释和一些例子。

                    【讨论】:

                    • 使用 select union all from dual 生成样本数据而不创建任何表的好主意
                    • @Jean-ChristopheBlanchard 尽管您可以很容易地使用values 子句。
                    • @Wildcard 在 PG 中,是的。在 Oracle 中,。至少在 11 岁之前没有。我还没有在 prod 中遇到 12 岁。
                    • 删除 from dual 以在 Redshift 中生成此数据
                    • Ivan,RANK 让我知道我相对于我前面的所有人的位置。 DENSE_RANK 告诉我绝对排名。我可能有第二高的薪水,但可能有 100 人在我前面。哪个更好取决于我要回答的问题。
                    猜你喜欢
                    • 1970-01-01
                    • 2014-10-20
                    • 1970-01-01
                    • 2012-05-25
                    • 2020-09-17
                    • 2010-11-13
                    • 1970-01-01
                    相关资源
                    最近更新 更多