【问题标题】:Row_number calculation in sql, oraclesql、oracle中的row_number计算
【发布时间】:2019-08-23 13:11:22
【问题描述】:

现在我在 sql 代码中遇到了一个小问题。

我不知道这个逻辑。

with res as (
select 
85,
2,
45,
34,
60,
2,
6,
4,
78,
6,
23,
45,
80,
80

from dual
)
 select * from res

我提到了 3 个标题 .1.input 2.Expected 3.Actual。 我的问题是根据输入天数设置一列,我们必须显示 rn 列。如果值是天 > 60,我们必须显示为零,下一行值将从 1 开始并打印为 2、3、4... 直到天 > 60。然后我们必须将天 > 60 设置为 0和 agin 从 1, 2,3 ... 仍然天 > 60 开始。它的循环直到值结束。

Input       Expected            Actual  

DAYS        DAYS    RN      DAYS    RN
85          85      0       85      1
4           4       1       4       2
32          32      2       32      3
7           7       3       7   4
5           5       4       5   5
66          66      0       66  6
14          14      1       14  7
25          25      2       25  8
2           2       3       2   9
9           9       4       9   10
70          70      0       70  11
80          80      0       80  12
6           6       1       6   13
3           3       2       3   14
1           1       3       1   15
78         78      0        78  16

【问题讨论】:

  • 您似乎对 RES 子查询中的值进行了排序。但是,行没有自然顺序(即使您以特定顺序编写它们)。你怎么知道“第一个”值是 85,“第二个”是 4,等等?它们是否按另一列排序,可能是“序列”列,或者日期或时间戳列等?

标签: sql oracle


【解决方案1】:

好的,首先...为了获得有意义的结果,您需要一种方法来对输入数据进行排序以获取每条记录的行号。您不能只依赖每个记录在列表中的位置,因为如果这些记录来自表,那么在 Oracle 中这是未定义的。

所以,假设我们将rn 列添加到您的res 表中,您需要做的就是:

select res.rn, 
       res.days, 
       res.rn - nvl(last_value(case 
                when res.days < 60 then null 
                else res.rn end) ignore nulls over (order by rn),0) lrn
from res;

nvl(last_value... 表达式查找具有 days >= 60 的最近输入记录的 rn(行号)。因此,如果记录的 rn 为 15,并且最近的记录为 days >= 60 是 13,然后该记录被重新编号为“2”。

为此,输入数据中的 rn 值必须从 1 开始并且没有间隙。如果您的真实数据不是这种情况,那么您将需要在此之前添加另一个 with 子句以执行 dense_rank 或以这种方式获取它们。

这是一个完整的示例,使用您的测试数据(来自您的预期结果):

with res (rn, days) as (
select 1, 85 from dual union all
select 2, 4 from dual union all
select 3, 32 from dual union all
select 4, 7 from dual union all
select 5, 5 from dual union all
select 6, 66 from dual union all
select 7, 14 from dual union all
select 8, 25 from dual union all
select 9, 2 from dual union all
select 10, 9 from dual union all
select 11, 70 from dual union all
select 12, 80 from dual union all
select 13, 6 from dual union all
select 14, 3 from dual union all
select 15, 1 from dual union all
select 16, 78 from dual
)
-- Above is just test data.. solution starts here
/* with ... */ 
select res.rn, res.days, res.rn - nvl(last_value(
     case when res.days < 60 then null else res.rn end) 
     ignore nulls over (order by rn),0) lrn
from res
+----+------+-----+
| RN | DAYS | LRN |
+----+------+-----+
|  1 |   85 |   0 |
|  2 |    4 |   1 |
|  3 |   32 |   2 |
|  4 |    7 |   3 |
|  5 |    5 |   4 |
|  6 |   66 |   0 |
|  7 |   14 |   1 |
|  8 |   25 |   2 |
|  9 |    2 |   3 |
| 10 |    9 |   4 |
| 11 |   70 |   0 |
| 12 |   80 |   0 |
| 13 |    6 |   1 |
| 14 |    3 |   2 |
| 15 |    1 |   3 |
| 16 |   78 |   0 |
+----+------+-----+

LRN 是您想要的结果中的“预期”RN。为简单起见,我省略了“实际”列,它们似乎与输入数据重复。

【讨论】:

    【解决方案2】:

    您没有包含您的实际选择语句。

    我猜是这样的:

     select res.*, row_number() OVER () AS RN from res
    

    你想像这样使用模数:

     select res.*, (row_number() OVER ()) % 5 AS RN from res
    

    【讨论】:

    • 该问题与row_number模4无关。
    • @mathguy 我正在查看他的示例代码并期待
    • 您在哪里看到与模 4 相关的内容,无论是在示例代码中还是在预期输出中?
    • @mathguy 就在期望输出中......现在我再次查看它是 mod 5 并且有一行 0 两次。但这就是我的样子。
    猜你喜欢
    • 1970-01-01
    • 2013-09-28
    • 1970-01-01
    • 2020-10-02
    • 2018-07-16
    • 2015-01-08
    • 2021-10-13
    • 2018-09-16
    • 1970-01-01
    相关资源
    最近更新 更多