如何扩展记录 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?的主要内容,如果未能解决你的问题,请参考以下文章