如何扩展记录 n 次并计算同一字段中日期的 Datediff?

Posted

技术标签:

【中文标题】如何扩展记录 n 次并计算同一字段中日期的 Datediff?【英文标题】:How can I expand records n-number of times and calculate Datediff for dates in same field? 【发布时间】:2018-02-14 17:35:10 【问题描述】:

我正在尝试根据记录的频率计数将表扩展 n 次,并根据“mxMonth”查找季度末日期或月末日期之间的 Datediff。请查看下面的所有详细信息,如果需要澄清,请告诉我...我知道这很复杂...

-----DLL

CREATE TABLE Reporting_Table (
    Credit_Line_NO    Varchar(10),
    noMonths         INT,
    EFFECTIVEDATE    Date,
    EXPIRY_DATE      Date,
    Amount           Money,
    mxDays           INT,
    mxFactor         decimal(5,4),
    Calc             Money)

INSERT INTO Reporting_Table (Credit_Line_NO, noMonths, EFFECTIVEDATE, EXPIRY_DATE, Amount, mxDays, mxFactor, Calc)
 Values('9938810','3','3/31/2018','6/12/2020','11718.75','90','1','11718.75') 

INSERT INTO Reporting_Table (Credit_Line_NO, noMonths, EFFECTIVEDATE, EXPIRY_DATE, Amount, mxDays, mxFactor, Calc)
 Values('2235461','1','6/30/2018','6/6/2019','12345','30','1','12345') 

INSERT INTO Reporting_Table (Credit_Line_NO, noMonths, EFFECTIVEDATE, EXPIRY_DATE, Amount, mxDays, mxFactor, Calc)
 Values('3365434','12','6/30/2018','6/30/2019','298523.36085','365','1.01388888888889','302669.518639583') 


 Select *, (DATEDIFF(MONTH,EFFECTIVEDATE,EXPIRY_DATE)/noMonths)+1 as FREQ
 From Reporting_Table

这会给我 FREQ,我想用 FREQ 号扩展每一行;所以我想复制 Credit_Line_NO 10 次、2235461 13 次和 3365434 1 次()如果 noMonths=12 然后 FREQ=1。

接下来,根据 noMonths,我知道 EFFECTIVEDATE 和 EXPIRY_DATE 之间有 10 个周期(季度周期,因为 noMonths = 3)。以下是 10 个季度末期。 我想计算每个 Quarter_End_Date 之间的天数(如果频率是每月,则在月末日期之间)。

第一季度结束日期为 90 天。每个后续计算都基于该季度的天数。最后,最后一个周期总是小于整个季度(如果周期是每月,则小于 1 个月),所以我想计算两者之间的实际天数

我有以下 cte,它为我做了一些非常有用的事情。我只想修改它以执行以下操作:

#1) insert number of rows equal to the FREQ
#2) get quarter-end dates (or month-end dates of frequency is monthly)
#3) get number of days between dates  

--CTE

with cte as (
    select 
        *, rn = row_number() over (partition by Credit_Line_NO order by REVIEW_FREQUENCY)
        from 
        TBL_FBNK_LIMIT_HIST
)
select
    *,
    SUBSTRING(REVIEW_FREQUENCY,10,2) as mxMonth,
    RIGHT(REVIEW_FREQUENCY,2) as mxDays,
    CAST(LEFT(REVIEW_FREQUENCY,8) as DATE) as mxStartDate,
    CAST(EXPIRY_DATE AS DATE) as mxEndDate,
    FREQ = CASE  WHEN SUBSTRING(REVIEW_FREQUENCY,10,2) = 01 THEN 30
                 WHEN SUBSTRING(REVIEW_FREQUENCY,10,2) = 03 THEN 90
                 WHEN SUBSTRING(REVIEW_FREQUENCY,10,2) = 12 THEN 365
           END,
    CAST(round((DATEDIFF(MONTH,cast(LEFT(REVIEW_FREQUENCY,8) as DATE),CAST(EXPIRY_DATE AS DATE)))/cast(LEFT(SUBSTRING(REVIEW_FREQUENCY, CHARINDEX('M',review_frequency)+1,LEN(REVIEW_FREQUENCY)),2) as decimal)+0.4,0) AS INTEGER) AS FREQUENCY
from
    cte a
WHERE REVIEW_FREQUENCY NOT LIKE '%DAILY%'
ORDER BY Credit_Line_NO, rn

我认为这需要更多的逻辑;像这样:

FROM cte a
CROSS JOIN (SELECT TOP (SELECT ISNULL(MAX(FREQUENCY)+1,0) FROM cte) rn = ROW_NUMBER() OVER (ORDER BY REVIEW_FREQUENCY))
WHERE B.RN < = A.FREQUENCY

当然会引发错误。

我使用的是 SQL Server 2008。

【问题讨论】:

在我看来,如果你有行,#2 和#3 对你来说会很容易。生成这样的行的最佳方法是使用计数表。您只需加入它的值 sqlservercentral.com/articles/T-SQL/62867 就像@SeanLange 所说,一个计数表可以解决问题,但您也可以使用recursive-cte。 是的,任何一个选项都可能有效。它实际上会是什么样子?有人可以发布一些代码吗?我测试了一些想法,包括我上面描述的,但到目前为止我还没有能够实现这一目标。 【参考方案1】:

我刚刚找到了解决这个问题的方法。以下脚本按预期工作。

;with cte as
(
  select Credit_Line_NO, noMonths, EFFECTIVEDATE, EXPIRY_DATE, Amount, mxDays, mxFactor, Calc,
         (DATEDIFF(MONTH,EFFECTIVEDATE,EXPIRY_DATE)/noMonths)+1 as FREQ,
         1 as Rec_Iteration
  from Reporting_Table
  where noMonths > 1
  union all  
  select Credit_Line_NO, noMonths, EFFECTIVEDATE, EXPIRY_DATE, Amount, mxDays, mxFactor, Calc,
         (DATEDIFF(MONTH,EFFECTIVEDATE,EXPIRY_DATE)/noMonths)+1 as FREQ,
         Rec_Iteration + 1
  from cte 
  where Rec_Iteration < FREQ
)
select Credit_Line_NO, noMonths, EFFECTIVEDATE, EXPIRY_DATE, Amount, mxDays, mxFactor, Calc,
    (DATEDIFF(MONTH,EFFECTIVEDATE,EXPIRY_DATE)/noMonths)+1 as FREQ
from cte
order by Credit_Line_NO,
         Rec_Iteration

【讨论】:

这看起来可行,但在这里要小心。使用递归 cte like 与循环几乎相同。 sqlservercentral.com/articles/T-SQL/74118 如果你有一个大数据集,这将表现得非常糟糕。一个计数表在这里的扩展性会更好。 是的,是的,这是有道理的。现在,我只想让它工作。在不久的将来,我可以花一些时间来弄清楚如何优化它。我对 Tally Table 进行了一些研究,但我仍然不确定它是如何工作的,除了列出数字 1-22497,这是我需要扩展的行数。 您可以通过加入一个计数表来使用它,通常使用

以上是关于如何扩展记录 n 次并计算同一字段中日期的 Datediff?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 之 扩展例子

oracle 日期计算

分组统计查询

如何在 VHDL 中使用“函数”从同一计算中返回多个变量?

如何对窗口中的某个字段进行排序以获得前 N 个值,并对 DolphinDB 中的相应字段进行聚合计算?

如何在时间戳字段中仅使用日期来选择记录?