Oracle中的ROWNUMBER函数

时间:2016-03-26 15:52:40

标签: sql oracle window-functions row-number

小解释:

我有一个名为passes的表,它与2个表(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;

2 个答案:

答案 0 :(得分:0)

PARTITION BY子句中的ORDER BYOVER中使用相同的字段毫无意义。

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

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

在你写的时候:

  

我希望从特定日期获得第100个(ROWNUMBER())通过情况=' F'按小时和分钟排序

...你实际上用语言说出了这些条款需要加入的内容:

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

所以你的主要错误是将小时 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
)

答案 1 :(得分:0)

这个怎么样?

首先,在执行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

最后,将其包装在外部查询中,您将过滤器应用于“百分之一”记录:

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

最后,如果需要调整任何部分(不同的过滤器,连接等),您可以自行运行每个级别的内部查询以检查中间结果,以确保最终结果就是你想要的。