sql查询解释:oracle的rank和partition

Posted

技术标签:

【中文标题】sql查询解释:oracle的rank和partition【英文标题】:Explanation of sql query : Rank and partition oracle 【发布时间】:2015-06-11 05:50:24 【问题描述】:

我正在使用 oracle 数据库并且卡在这个查询上,我不明白它是如何工作的,我已经删除了所有不必要的信息并且查询已经归结为:

 select RANK () OVER (PARTITION BY A_pk ORDER BY B_pk DESC) as column from Table_C

有人能解释一下这是如何工作的吗?

【问题讨论】:

本教程很好地解释了窗口函数:postgresql.org/docs/current/static/tutorial-window.html 我正在使用 oracle db,postgresql 的概念也适用于 oracle 吗? @a_horse_with_no_name 是的,是ANSI SQL 99标准函数 【参考方案1】:

假设你有下表:

SELECT *, 
       ROW_NUMBER() OVER(PARTITION BY col1 ORDER BY col2) AS [ROW_NUMBER],
       RANK() OVER(PARTITION BY col1 ORDER BY col2) [RANK],
       DENSE_RANK() OVER(PARTITION BY col1 ORDER BY col2) [DENSE_RANK]
FROM SomeTable

col1    col2  |  ROW_NUMBER RANK    DENSE_RANK
1       1     |  1          1       1
1       1     |  2          1       1
1       5     |  3          3       2
1       5     |  4          3       2
1       9     |  5          5       3
1       9     |  6          5       3
2       1     |  1          1       1
2       1     |  2          1       1
2       1     |  3          1       1
2       3     |  4          4       2
2       3     |  5          4       2

ROW_NUMBER: 这些是window ranking 函数。这意味着当您按某个列进行分区时,函数在该分区的窗口中起作用。想象一下:

col1    col2
/*------*\
|1      1|
|1      1|
|1      5|  <--window 1
|1      5|
|1      9|
|1      9|
\*------*/

/*------*\
|2      1|
|2      1|
|2      1|  <--another window 2
|2      3|
|2      3|
\*------*/

当窗口改变时,一切都会重置!因此,对于ROW_NUMBER,您按col2 订购并按该顺序分配增量编号。当窗口更改时,功能重置并从1开始。

排名:

此函数将计算col2 的值小于当前行中col2 的值加1 的行数。例如在window 1col2 = 5 的行有2 行col2 = 1 ,所以2 + 1 = 3。对于 col2 = 9 的行,有 4 行,所以 4 + 1 = 5

DENSE_RANK:

它与RANK 相同,但它计算前面的 DISTINCT 值!例如,对于 col2 = 9 的行,col2 = 1 and 5 有 2 个不同的值,所以 2 + 1 = 3

【讨论】:

【参考方案2】:

    根据A_pk 列中的值将表格划分为“windows”:

     A_pk     |  B_pk
    develop   |    11
    develop   |     7
    develop   |     9
    develop   |     8
    develop   |    10
    *** window ***
    personnel |     5
    personnel |     2
    *** window ***
    sales     |     3
    sales     |     1
    sales     |     4
    

    B_pk desc订购每个“窗口”:

     A_pk     |  B_pk
    develop   |    11
    develop   |    10
    develop   |     9
    develop   |     8
    develop   |     7
    *** window ***
    personnel |     5
    personnel |     2
    *** window ***
    sales     |     4
    sales     |     3
    sales     |     1
    

    按窗口返回每行的排名(它所在的“位置”):

    1
    2
    3
    4 
    5
    *** window ***
    1
    2
    *** window ***
    1
    2
    3
    

【讨论】:

【参考方案3】:

让我们通过对 SCOTT 模式中的示例 EMP 表的这个简单查询来理解:

SQL> SELECT empno,
  2    deptno,
  3    sal,
  4    rank() over(partition BY deptno order by sal) rn
  5  FROM emp;

     EMPNO     DEPTNO        SAL         RN
---------- ---------- ---------- ----------
      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

14 rows selected.

SQL>

RANK 函数是一个内置的分析函数,用于对一组行中的记录进行排名。窗口中的 PARTITION BY 子句对行进行分组,而 ORDER BY 子句告诉如何排名,即每个组中的哪一行将保持第一个排名,然后按该顺序将下一个排名分配给下一行。

集团 排序 分配排名

因此,在上面的示例中,行按部门分组按薪水排序。在每个组中,从最低工资(升序)开始分配排名。当出现平局时,排名不会增加,但是,值发生变化的下一行不会有连续的顺序。这就是这里发生的事情:

7654         30       1250          2
7521         30       1250          2
7844         30       1500          4

排名不连续,因为工资1250 的两行之间存在平局。要保持序列连续,您需要使用 DENSE_RANK

【讨论】:

以上是关于sql查询解释:oracle的rank和partition的主要内容,如果未能解决你的问题,请参考以下文章

Oracle 查询/SQL 调优

ORACLE分组排序查询

Oracle用户登录和连接查询特殊排序over()rank()decode() case whenUNION/UNION ALL

oracle sql rank函数取排序值

Oracle EBS AR 客户取数SQL

Oracle中排序函数的用法之ROW_NUMBER()_RANK()_DENSE_RANK() OVER()的区别