简体   繁体   English

Oracle中的ROWNUMBER函数

[英]ROWNUMBER function in Oracle

Little explanation: 小解释:

I have a table called passes and it's linked with 2 tables ( services (cod_serv) and atend (pass)). 我有一个名为passes的表,它与2个表( services (cod_serv)和atend (通过))链接在一起。 Passes can be duplicated for different services. 可以为不同的服务复制通行证。

Eg.: If I have 3 services, I can have 3 passes nº 01, BUT not 2 passes nº 1 for the same service (I defined it in my composite primary key). 例如:如果我有3个服务,那么对于同一服务,我可以有3个通过nº01, 没有2个通过nº1(我在复合主键中定义了它)。

For tests, I added 102 passes (all with situation = "F" and with the same date (today)). 为了进行测试,我添加了102个通行证(所有情况都为“ F”且日期(今天)相同)。 Then I added 34 passes for each service (I have 3 services). 然后,我为每个服务添加了34个通行证(我有3个服务)。

The following query is to show how the schema more or less defined. 以下查询显示了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
...        ...        ...            ...    ...            ... 

Then, I want to get the 100th ( ROWNUMBER() ) pass (as it's showing below it's 21) from a specific date with the situation = 'F' ordering by hour and min. 然后,我想从特定日期获取第100次( ROWNUMBER() )通过(如下图所示,其值为21),情况='F',按小时和分钟排序。

Row Number 100: 第100行:

21         26/03/16   3              F      14             34   

The following query is returning nothing and I can't figure out why. 以下query未返回任何内容,我不知道为什么。 By the way, I have more than 100 passes with this situation. 顺便说一句,在这种情况下,我有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;

EDIT: 编辑:

My query at the moment: 我目前的查询:

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;

Having the same fields in PARTITION BY and ORDER BY in an OVER clause makes little sense. OVER子句的PARTITION BYORDER BY中具有相同的字段几乎没有意义。

The PARTITION BY clause should list the fields that define the group in which you start counting records from 1. PARTITION BY子句应列出定义从1开始对记录进行计数的组的字段。

The ORDER BY clause defines the order in which records are counted within that group. ORDER BY子句定义该组中记录的计数顺序。

As you write: 在您撰写时:

I want to get the 100th ( ROWNUMBER() ) pass from a specific date with the situation = 'F' ordering by hour and min 我想从特定日期获得第100次( ROWNUMBER() )传递,情况='F',按小时和分钟排序

... you actually say in words what needs to be put in these clauses: ...您实际上是在说这些条款中需要写的内容:

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

So your main mistake was to put hour and min in the PARTITION BY clause, making the record count starting from 1 as soon as a minute difference was found, giving most of your records the number 1. 因此,您的主要错误是将小时分钟放在PARTITION BY子句中,一旦发现分钟差,就使记录计数从1开始,大多数记录的编号为1。

Edit 编辑

It seems that Oracle does not retain the same row number when it is not selected. 似乎没有选择时,Oracle不会保留相同的row号。 This is probably because the ORDER BY hour, min is not deterministic. 这可能是因为ORDER BY hour, min不确定。 Whatever the reason, it can be solved by selecting the row in the outer query: 无论是什么原因,都可以通过选择外部查询中的row来解决:

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

If you only need the pass, you can wrap that query again: 如果只需要通过,则可以再次包装该查询:

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

How about this? 这个怎么样?

First, before doing row_number() , apply ALL of your filters (since you don't want to count the rows that you're going to filter out): 首先,在执行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)

Now, wrap that in an outer query where you apply row_number() : 现在,将其包装在外部查询中,在其中应用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

Finally, wrap that in an outer query where you apply the filter for the "hundredth" record: 最后,将其包装在外部查询中,在其中将过滤器应用于“一百”条记录:

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

Lastly, if any parts need adjusting (different filters, joins, etc.), you can run each of these levels of inner queries on their own to check your intermediate results to make sure your final result is what you want. 最后,如果任何部分需要调整(不同的过滤器,联接等),则可以自行运行这些内部查询级别中的每一个,以检查中间结果,以确保最终结果是所需的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM