Oracle 中的 ROWNUMBER 函数

ROWNUMBER function in Oracle

小说明:

我有一个名为 passes 的 table,它与 2 tables (services (cod_serv) 和 atend (经过))。可以为不同的服务复制通行证。

例如:如果我有 3 项服务,我可以有 3 次 nº 01 传递,但是 不是 2 次传递 nº 1 用于相同的服务(我在我的复合主项中定义了它键)。

对于测试,我添加了 102 次通过(所有情况都为 "F" 且日期相同(今天))。然后我为每项服务添加了 34 通行证(我有 3 项服务)。

下面的查询是为了显示 schema 或多或少是如何定义的。

SELECT DISTINCT s.pass, s.data, cod_serv, situation, hour, min
FROM passes 
JOIN atend a ON s.pass = a.pass;

PASS       DATA       COD_SERV       S      HOUR           MIN
-----      --------   ---------      -      -------        -------
04         26/03/16   2              F      12             24
04         26/03/16   1              F      13             27
13         26/03/16   1              F      14             26
18         26/03/16   3              F      14             27
18         26/03/16   2              F      14             28
15         26/03/16   1              F      14             29
10         26/03/16   3              F      14             30
...        ...        ...            ...    ...            ... 

然后,我想从特定日期获得第 100 (ROWNUMBER()) 次通过(如下所示为 21),情况 = 'F' 按小时和分钟排序。

第 100 行:

21         26/03/16   3              F      14             34   

以下 query 没有返回任何内容,我不明白为什么。顺便说一句,我有超过100次通过这种情况。

SELECT DISTINCT pass, data, cod_serv, situation FROM
  (SELECT DISTINCT a.pass, s.data, cod_serv, situation,
          ROW_NUMBER() OVER(PARTITION BY situation, hour, min
                            ORDER BY situation, hour, min) row
   FROM passes s
   JOIN atend a ON s.pass = a.pass
   WHERE situation = 'F' AND
         TRUNC(a.data) = TRUNC('some date'))
WHERE row = 100;

编辑:

我现在的查询:

SELECT DISTINCT pass, cod_serv FROM
  (SELECT DISTINCT s.pass, cod_serv,
          ROW_NUMBER() OVER(PARTITION BY TRUNC(s.data)
                            ORDER BY a.hour, a.min) row
   FROM passes s
   JOIN atend a ON s.pass = a.pass
   WHERE s.situation = 'F' AND
         TRUNC(s.data) = TRUNC(SYSDATE))
WHERE row = 100;

PARTITION BYORDER BY 中的 OVER 子句中具有相同的字段毫无意义。

PARTITION BY 子句应列出定义您从 1 开始计算记录的组的字段。

ORDER BY 子句定义记录在该组中的计数顺序。

如您所写:

I want to get the 100th (ROWNUMBER()) pass from a specific date with the situation = 'F' ordering by hour and min

...你实际上用文字说出这些条款中需要放入的内容:

 ROW_NUMBER() OVER(PARTITION BY data, situation ORDER BY hour, min)

所以你的主要错误是把小时分钟放在PARTITION BY子句中,使记录计数从一旦发现一分钟的差异,立即为 1,为您的大部分记录分配数字 1。

编辑

好像Oracle在没有选择的时候没有保留相同的row号。这可能是因为 ORDER BY hour, min 不是确定性的。无论是什么原因,都可以通过在外部查询中选择row来解决:

SELECT pass, row FROM ( ... etc ...) WHERE row = 100

如果您只需要通行证,您可以再次包装该查询:

SELECT pass FROM (
    SELECT pass, row FROM ( ... etc ...) WHERE row = 100
)

这个怎么样?

首先,在执行 row_number() 之前,应用所有过滤器(因为您不想计算要过滤掉的行数):

SELECT s.pass, s.data, cod_serv, s.situation, a.hour, a.min
FROM passes s
JOIN atend a ON s.pass = a.pass
WHERE s.situation = 'F' 
AND TRUNC(s.data) = TRUNC(SYSDATE)

现在,将其包装在您应用 row_number():

的外部查询中
SELECT pass, data, cod_serv, situation, hour, min,
       rowseq=row_number() over (order by hour, min)
FROM (
    SELECT s.pass, s.data, cod_serv, s.situation, a.hour, a.min
    FROM passes s
    JOIN atend a ON s.pass = a.pass
    WHERE s.situation = 'F' 
    AND TRUNC(s.data) = TRUNC(SYSDATE)
) t1

最后,将其包装在外部查询中,在该查询中为 "hundredth" 记录应用过滤器:

SELECT pass, data, cod_serv, situation, hour, min
FROM (
    SELECT pass, data, cod_serv, situation, hour, min,
           rowseq=row_number() over (order by hour, min)
    FROM (
        SELECT s.pass, s.data, cod_serv, s.situation, a.hour, a.min
        FROM passes s
        JOIN atend a ON s.pass = a.pass
        WHERE s.situation = 'F' 
        AND TRUNC(s.data) = TRUNC(SYSDATE)
    ) t1
WHERE rowseq = 100

最后,如果任何部分需要调整(不同的过滤器、连接等),您可以 运行 这些级别的内部查询中的每一个都自己检查您的中间结果,以确保您的 最终结果如你所愿