【问题标题】:DATEADD not returning correct dates for some rowsDATEADD 未返回某些行的正确日期
【发布时间】:2019-05-21 20:33:57
【问题描述】:

该函数应在当前日期之后返回一个新日期,并添加 num_of_flows。 num_of_flows 是一个整数值

ALTER  function [dbo].[M20_22_GetLoanMaturityDate_FIN_10]
(
    @AcctAcid varchar(50),
    @ScheduleNum varchar(50),
    @bank_id varchar(6) = '03'
)
returns varchar(50)
as 
BEGIN
    Declare @lMaturityDate varchar(50)
    begin
            select @lMaturityDate = 
            case Finacle_Lrs.LR_FREQ_TYPE   
                             when 'W' then  dateadd(day, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 7,Finacle_Lrs.FLOW_START_DATE)
                             when 'F' then  dateadd(day, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 14,Finacle_Lrs.FLOW_START_DATE)
                             when 'M' then  (dateadd(month, Finacle_Lrs.NUM_OF_FLOWS - 1, Finacle_Lrs.FLOW_START_DATE))
                             when 'Q' then  (dateadd(month, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 3, Finacle_Lrs.FLOW_START_DATE))
                             when 'H' then  dateadd(month, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 6, Finacle_Lrs.FLOW_START_DATE)
                             when 'Y' then  dateadd(month, (Finacle_Lrs.NUM_OF_FLOWS - 1) * 12, Finacle_Lrs.FLOW_START_DATE)
                      end
            from    [TEST_EIMDW_Archive].[ARCHOWN].[FINCL10_LRS] Finacle_Lrs
            where   Finacle_Lrs.acid = @AcctAcid
            and Finacle_Lrs.shdl_num = @ScheduleNum
            and Finacle_Lrs.FLOW_ID in ('PRDEM','EIDEM')
            AND Finacle_Lrs.ACTIVE_FLAG = 'Y' AND Finacle_Lrs.DELETE_FLAG= 'N'
            and Finacle_Lrs.bank_id = @bank_id
            and Finacle_Lrs.FLOW_START_DATE = ( select max(a.FLOW_START_DATE)
                            from   [TEST_EIMDW_Archive].[ARCHOWN].[FINCL10_LRS] a
                            where  a.ACID = Finacle_Lrs.ACID
                                and    a.SHDL_NUM = Finacle_Lrs.SHDL_NUM
                            and    a.FLOW_ID in ('PRDEM', 'EIDEM') AND a.ACTIVE_FLAG = 'Y' AND a.DELETE_FLAG='N' and a.bank_id = @bank_id
        );
end
        return isnull(@lMaturityDate,null);

END

在做了一些检查之后,我注意到有一天在比较 oracle 数据库上的原始代码时,altest 低估了 19629 行。请看oracle版本的代码:

FUNCTION GetLoanMaturityDate(AcctAcid VARCHAR2, ScheduleNum VARCHAR2) RETURN DATE IS
        lMaturityDate DATE;
    BEGIN
        begin
            select decode(lrs.LR_FREQ_TYPE, 'W', lrs.FLOW_START_DATE + (lrs.NUM_OF_FLOWS - 1) * 7,
                            'F', lrs.FLOW_START_DATE + (lrs.NUM_OF_FLOWS - 1) * 14,
                            'M', add_months(lrs.FLOW_START_DATE, lrs.NUM_OF_FLOWS - 1) ,
                            'Q', add_months(lrs.FLOW_START_DATE, (lrs.NUM_OF_FLOWS - 1) * 3),
                            'H', add_months(lrs.FLOW_START_DATE, (lrs.NUM_OF_FLOWS - 1) * 6),
                            'Y', add_months(lrs.FLOW_START_DATE, (lrs.NUM_OF_FLOWS - 1) * 12)
                     )
            into    lMaturityDate
            from    lrs
            where   lrs.acid = AcctAcid
            and lrs.shdl_num = ScheduleNum
            and lrs.FLOW_ID in ('PRDEM','EIDEM')
            and lrs.FLOW_START_DATE = ( select max(a.FLOW_START_DATE)
                            from   lrs a
                            where  a.ACID = lrs.ACID
                                and    a.SHDL_NUM = lrs.SHDL_NUM
                            and    a.FLOW_ID in ('PRDEM', 'EIDEM')
                               ) ;
        exception
            when no_data_found then
                lMaturityDate:=NULL;
        end;

        return lMaturityDate;
    END GetLoanMaturityDate;

这也是我运行的比较查询以查看不正确的行:

SELECT eim.acid as eim_acid,it.[ACID] as it_acid,
eim.[MATURITY_DATE] as eim_maturity_date,it.[MATURITY_DATE] as it_maturity_date ,
eim.[DAYS_TO_MATURITY] as eim_DAYS_TO_MATURITY,it.[DAYS_TO_MATURITY] as it_DAYS_TO_MATURITY,(it.[DAYS_TO_MATURITY]-eim.[DAYS_TO_MATURITY]) as diff
FROM [TEST_EIMDW_BOJ_REPORTS].[BOJOWN].[loans_maturity_profile] eim 
inner join [dbo].[IT_LOANS_MATURITY_PROFILE] it on eim.acid= it.acid
where eim.MATURITY_DATE != it.MATURITY_DATE 

最后,下面的查询结果显示了正确结果集与我目前尝试在 sql server 上修复的结果集的比较:

【问题讨论】:

  • 这里要小心。您正在计算一个日期,然后返回一个 varchar。您应该返回日期而不是字符串。此外,sql server 中的标量函数的性能也是出了名的差。如果有很多操作,转换为内联表值函数可能是个好主意。
  • @SeanLange 指出,但是,我正在寻找一种在 sql server 中重现 Oracle 代码的方法。有什么想法吗?
  • 我对甲骨文并不精通,并且承认戈登在该领域的知识比我所拥有的要好得多。请看下面他的回答。可能不是你想听到的。
  • 看起来他总是需要每月的最后一天。使用“月末”(EOMONTH ( start_date [, month_to_add ] ) )函数会在这里产生更好的结果。

标签: sql sql-server oracle tsql


【解决方案1】:

补充一下 Gordon 所说的,Oracle 的 ADD_MONTHS 函数的确切行为是,如果源日期是其月份的最后一天,那么返回日期也是结果月份的最后一天(无论源日期的月份长度)。

SQL Server 没有类似的功能。

哪种实现是正确的,或者是否重要,将取决于您的具体情况。

【讨论】:

    【解决方案2】:

    Oracle 的 add_months() 和 SQL Server 的 dateaddd(month) 具有不同的语义,尤其是在月底。

    所以:

    select add_months(date '2019-02-28', 1)
    from dual
    
    --> 2019-03-31
    

    (见db<>fiddle

    鉴于:

    select dateadd(month, 1, '2019-02-28')
    
    --> 2019-03-28
    

    (见db<>fiddle

    在 SQL Server 中模拟 Oracle 行为可能有点棘手。我什至不确定这是否可取。

    【讨论】:

    • 应该是"select add_months(date '2019-02-28', 1) from dual"
    • @Piotr 。 . .我发誓,当我实际测试它时,我的问题代码似乎更糟。无论如何,dbfiddle 是正确的。
    • @GordonLinoff 我想要实现的目标是可取的
    • 无法构造数据类型日期,某些参数的值无效。
    【解决方案3】:

    SQL Server“月末” - EOMONTH (start_date[, month_to_add ]) 函数的行为类似于 ORACLE add_months 在该月的最后一天。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-06
      • 2011-07-09
      • 1970-01-01
      • 1970-01-01
      • 2015-12-14
      相关资源
      最近更新 更多