有条件的ROW_NUMBER()跳过仍然计数它们的空值

时间:2018-11-19 15:33:48

标签: sql plsql oracle11g

我正在尝试按照[先提取然后再收费;根据列NETWORKCD是否为空,先提取然后收费。但是,即使未显示数字,我的row_number公式仍在计算Null,例如:

+--------+-------------+------------+-----------+-------------+
| Acctid | Transaction |  PostDate  | NetworkCd | PeriodCount |
+--------+-------------+------------+-----------+-------------+
|  12345 | Withdrawal  | 10/4/2018  | FRGN      |           1 |
|  12345 | Fee         | 10/4/2018  |           |             |
|  12345 | Withdrawal  | 10/11/2018 | FRGN      |           3 |
|  12345 | Fee         | 10/11/2018 |           |             |
|  12345 | Withdrawal  | 10/22/2018 | FRGN      |           5 |
|  12345 | Fee         | 10/22/2018 |           |             |
+--------+-------------+------------+-----------+-------------+

我对PeriodCount使用以下公式

(case when networkcd is not null 
      then row_number() over (partition by acctid order by postdate) 
 end) PeriodCount

我期望PeriodCount计数为[1,2,3]而不是[1,3,5],如下所示:

+--------+-------------+------------+-----------+-------------+
| Acctid | Transaction |  PostDate  | NetworkCd | PeriodCount |
+--------+-------------+------------+-----------+-------------+
|  12345 | Withdrawal  | 10/4/2018  | FRGN      |           1 |
|  12345 | Fee         | 10/4/2018  |           |             |
|  12345 | Withdrawal  | 10/11/2018 | FRGN      |           2 |
|  12345 | Fee         | 10/11/2018 |           |             |
|  12345 | Withdrawal  | 10/22/2018 | FRGN      |           3 |
|  12345 | Fee         | 10/22/2018 |           |             |
+--------+-------------+------------+-----------+-------------+

我想念什么?

5 个答案:

答案 0 :(得分:3)

它仍然在第一,第三和第五行显示一个值-因此遇到这些行中的每一行时的行计数都是正确的。它是整个结果集中的行号,而不是非空值中的行号。您的case表达式将决定是否显示该值,而不影响其查找方式。

您可以使用dense_rank()来获得所需的结果;

with your_table (Acctid, Transaction, PostDate, NetworkCd) as (
          select 12345, 'Withdrawal', to_date('10/4/2018', 'MM/DD/YYYY'), 'FRGN' from dual
union all select 12345, 'Fee', to_date('10/4/2018', 'MM/DD/YYYY'), null from dual
union all select 12345, 'Withdrawal', to_date('10/11/2018', 'MM/DD/YYYY'), 'FRGN' from dual
union all select 12345, 'Fee', to_date('10/11/2018', 'MM/DD/YYYY'), null from dual
union all select 12345, 'Withdrawal', to_date('10/22/2018', 'MM/DD/YYYY'), 'FRGN' from dual
union all select 12345, 'Fee', to_date('10/22/2018', 'MM/DD/YYYY'), null from dual
)
select Acctid, Transaction, PostDate, NetworkCd,
(case when networkcd is not null then dense_rank() over (partition by acctid order by postdate) end) as periodcount
from your_table;

    ACCTID TRANSACTIO POSTDATE   NETW PERIODCOUNT
---------- ---------- ---------- ---- -----------
     12345 Withdrawal 2018-10-04 FRGN           1
     12345 Fee        2018-10-04                 
     12345 Withdrawal 2018-10-11 FRGN           2
     12345 Fee        2018-10-11                 
     12345 Withdrawal 2018-10-22 FRGN           3
     12345 Fee        2018-10-22                 

...这样可以抑制生成值中的间隙。 From the docs

  

DENSE_RANK计算行的有序组中某一行的排名,并将排名返回为NUMBER。等级是从1开始的连续整数。...

答案 1 :(得分:1)

Alex Poole 的答案有效,但依赖于您的空行与您要计算的非空行具有相同的 POSTDATE 的事实。如果您将日期更改为彼此不同,您会看到密集排名失败:

with your_table (Acctid, Transaction, PostDate, NetworkCd) as (
              select 12345, 'Withdrawal', to_date('10/1/2018', 'MM/DD/YYYY'), 'FRGN'
    union all select 12345, 'Fee', to_date('10/2/2018', 'MM/DD/YYYY'), null
    union all select 12345, 'Withdrawal', to_date('10/3/2018', 'MM/DD/YYYY'), 'FRGN'
    union all select 12345, 'Fee', to_date('10/4/2018', 'MM/DD/YYYY'), null
    union all select 12345, 'Withdrawal', to_date('10/5/2018', 'MM/DD/YYYY'), 'FRGN'
    union all select 12345, 'Fee', to_date('10/6/2018', 'MM/DD/YYYY'), null
    )

select
    Acctid,
    Transaction,
    PostDate,
    NetworkCd,
    case when networkcd is not null then dense_rank() over (partition by Acctid order by PostDate) end as PeriodCount,
    dense_rank() over (partition by Acctid order by PostDate) as DenseRank
from your_table
order by Acctid, PostDate, Transaction
;

收益

acctid  transaction  postdate    networkcd  periodcount  denserank
------  -----------  ----------  ---------  -----------  ---------
12345   Withdrawal   2018-10-01  FRGN       1            1
12345   Fee          2018-10-02                          2
12345   Withdrawal   2018-10-03  FRGN       3            3
12345   Fee          2018-10-04                          4
12345   Withdrawal   2018-10-05  FRGN       5            5
12345   Fee          2018-10-06                          6

(在右侧,显示了没有空条件的dense_rank 的结果)所以它适用于您的情况,但总体上并不可靠。

Kevin Siemons 的答案效果更好:它分别计算空行和非空行,您可以简单地隐藏您对空行所做的计数:

with your_table (Acctid, Transaction, PostDate, NetworkCd) as (
              select 12345, 'Withdrawal', to_date('10/1/2018', 'MM/DD/YYYY'), 'FRGN'
    union all select 12345, 'Fee', to_date('10/2/2018', 'MM/DD/YYYY'), null
    union all select 12345, 'Withdrawal', to_date('10/3/2018', 'MM/DD/YYYY'), 'FRGN'
    union all select 12345, 'Fee', to_date('10/4/2018', 'MM/DD/YYYY'), null
    union all select 12345, 'Withdrawal', to_date('10/5/2018', 'MM/DD/YYYY'), 'FRGN'
    union all select 12345, 'Fee', to_date('10/6/2018', 'MM/DD/YYYY'), null
    )

select
    Acctid,
    Transaction,
    PostDate,
    NetworkCd,
    case when networkcd is not null then row_number() over (partition by Acctid, NetworkCd is not null order by PostDate) end as PeriodCount,
    row_number() over (partition by Acctid, NetworkCd is not null order by PostDate) as RowNumber
from your_table
order by Acctid, PostDate, Transaction
;

收益

acctid  transaction  postdate    networkcd  periodcount  rownumber
------  -----------  ----------  ---------  -----------  ---------
12345   Withdrawal   2018-10-01  FRGN       1            1
12345   Fee          2018-10-02                          1
12345   Withdrawal   2018-10-03  FRGN       2            2
12345   Fee          2018-10-04                          2
12345   Withdrawal   2018-10-05  FRGN       3            3
12345   Fee          2018-10-06                          3

我建议——使用 case when networkcd is not null then row_number() over (partition by Acctid, NetworkCd is not null order by PostDate) end as PeriodCount

答案 2 :(得分:0)

ROW_NUMBER()函数无法按预期工作,但您可以这样做:

select t.*,
       (select count(*)
        from table t1
        where t1.acctid = t.acctid and t1.PostDate <= t.PostDate and
              t1.networkcd is not null 
       ) as PeriodCount
from table t;

答案 3 :(得分:0)

它看起来不是空值,而是空字符串。 SQL在代码中将以不同的方式对待。

尝试:

case when networkcd = '' then row_number()....

答案 4 :(得分:0)

尝试将 partition by acctid 更改为 partition by acctid, NetworkCd IS NOT NULL