根据日期重置计数器值

Posted

技术标签:

【中文标题】根据日期重置计数器值【英文标题】:Reseting Counter Value based on Date 【发布时间】:2020-06-04 23:04:06 【问题描述】:

在查询 Oracle 数据库时,我正在构建一个表,用于计算从 issue_date 开始存在的每一年的许可证年龄。比如:

LICENSE_NUMBER    ISSUE_ANNIVERSARY   LICENSE_AGE
1234              13-JUN-83           1
1234              13-JUN-84           2
1234              13-Jun-85           3
1234              13-Jun-86           4
1234              13-Jun-87           5
1234              13-Jun-88           6
1234              13-Jun-89           7

我得到了一个警告。当 ISSUE_ANNIVERSARY 到 1986 年时,我必须将年龄重新设置为 1。所以,我想要的结果如下所示:

LICENSE_NUMBER    ISSUE_ANNIVERSARY   LICENSE_AGE
1234              13-JUN-83           1
1234              13-JUN-84           2
1234              13-Jun-85           3
1234              13-Jun-86           1
1234              13-Jun-87           2
1234              13-Jun-88           3
1234              13-Jun-89           4

我的方法是设置条件 CASE 子句以在 ISSUE_ANNIVERSARY 包含 1986 年时重置 LICENSE_AGE 但是我认为我的语法不正确。我尝试了几种方法,但不断出错。我的最新尝试如下。我并没有挂断这种 CASE 方法,但是我必须记住,我在 1986 年之前、1986 年期间和 1986 年之后都颁发了许可证,所以我认为一个条件最好。感谢您提出任何建议!

WITH LICENSE (license_number, issue_anniversary, expiry_date, license_age) AS 
    (
    SELECT lic.license_number, lic.issue_date, lic.expiry_date, 1
    FROM license_table lic

    UNION ALL

    SELECT license_number, ADD_MONTHS(issue_anniversary, 12), expiry_date,  
    CASE 
     WHEN EXTRACT(YEAR FROM ADD_MONTHS(issue_anniversary, 12) = 1986 THEN 1
    ELSE
     license_age + 1
    END
    FROM   license
    WHERE expiry_date <= sysdate and license_number = 1234
    )

SELECT license_number,
       issue_anniversary,
       license_age     
FROM   license

【问题讨论】:

是什么让您认为您的方法不正确? (1) 同时存储日期和年龄违反了第三范式,如果它们不同步,就有丢失 R/I 的风险。考虑只存储日期。您可以将年龄包含在计算列中,也可以改用视图。 (2) 您是否考虑过 License_Year 表?然后,您可以加入它以确定如何计算年龄。否则,您将无法将 1986 硬编码到您的代码中。 @JohnWu:(1) 他们没有存储它,而是在递归查询中动态计算它。 @GMB。好问题。从理论上讲,我觉得方法是正确的。至少,如果我从我的 python 背景中绘制,我就在正确的范围内,但是我会遇到各种不同的错误,这取决于我尝试的方法,所以我觉得我需要问一下。另外,感谢您的澄清。是的,我想计算字段,而不是存储它。 @Mike:乍一看,您的代码对我来说看起来不错。您应该对其进行测试,并告知您是否有一些具体问题。 【参考方案1】:

你可以使用row_number():

select t.*,
       row_number() over (partition by license_number,
                                       case when ISSUE_ANNIVERSARY < date '1986-01-01' then 1 else 0 end
                          order by ISSUE_ANNIVERSARY
                         ) as license_age
from license_table lt;

【讨论】:

@George Linoff。谢谢你的建议。我之前没有使用过 OVER 子句和分区,我一直在玩一些使用它的代码。虽然我解决了自己的问题,但我肯定学到了一些有用的东西,我相信我可以使用你的逻辑。感谢您的贡献!

以上是关于根据日期重置计数器值的主要内容,如果未能解决你的问题,请参考以下文章

Python:如何根据日期时间获取值的计数

如何在重置之前向日志添加值(CoreData 和 Swift)

根据参数 -Oracle 重新启动 sum(over) 函数

在 pyspark 中,基于变量字段进行分组,并为特定值添加一个计数器(当变量更改时重置)

用于 CVC3 生成的 EMV 芯片中存储的应用程序事务计数器是不是有最大值?如果是,该值是不是会随时重置?

重置窗口函数的计数器