SQL Server查询将季度和半年度本金和利息支付转换为月度值

时间:2016-07-06 02:56:08

标签: sql sql-server sql-server-2014

我们使用SQL Server 2014作为主要报告数据库,我们的报告需要一些非常具体的数据操作。我们必须处理的数据是本金和利息支付的时间表,可以以各种类型的系列(即季度,半年度,年度等)呈现。要确定月收入,需要将这些本金和利息支付从原始格式重新组织为每月计划。以下是原始数据格式的示例:

原始现金流量表

Cashflow_Date     Principal     Interest
-------------     ---------     --------
2015-12-15        0             1000.00
2016-06-15        0             1000.00
2016-12-15        10000.00      1000.00

以下是需要的格式:

所需的现金流量表

Cashflow_Date     Principal     Interest
-------------     ---------     --------
2015-12-15        0             166.667
2016-01-15        0             166.667
2016-02-15        0             166.667
2016-03-15        0             166.667
2016-04-15        0             166.667
2016-05-15        0             166.667
2016-06-15        0             166.667
2016-07-15        0             166.667
2016-08-15        0             166.667
2016-09-15        0             166.667
2016-10-15        0             166.667
2016-11-15        0             166.667
2016-12-15        10000.00      1000.00

基本上,原始时间表付款之间的月份需要与原始付款日期一起返还,原始付款需要在原始付款日期之间分为每月金额(即2015/12年度的1000/6 = 166.667) -15至2016-05-15)。最后一个付款日期(在本例中为2016-12-15)将保持原样。在整个原始计划中,本金和利息的支付不保证是相同的,因此必须适当地划分付款。

我们遗憾的是,当前进程在游标内部使用游标和循环(我知道非常糟糕)以生成所需的结果集。任何人都可以提供对基于集合的查询的任何见解,这些查询可能能够更快地生成相同的结果吗?非常感谢任何帮助。

更新了方案

根据下面发布的问题,如果在原始计划中支付了一次性本金或利息,则这些付款会相应地进行分配。例如,如果在2016-06-15进行一次性本金支付,则月收入计划将以这种方式反映:

边缘案例所需的现金流量表

Cashflow_Date     Principal     Interest
-------------     ---------     --------
2015-12-15        0             166.667
2016-01-15        0             166.667
2016-02-15        0             166.667
2016-03-15        0             166.667
2016-04-15        0             166.667
2016-05-15        0             166.667
2016-06-15        208.33        166.667
2016-07-15        208.33        166.667
2016-08-15        208.33        166.667
2016-09-15        208.33        166.667
2016-10-15        208.33        166.667
2016-11-15        208.33        166.667
2016-12-15        10000.00      1000.00

2 个答案:

答案 0 :(得分:0)

大概你想要这样的东西:

DECLARE @ TABLE (Cashflow_Date DATE, Principal DECIMAL (10,2), Interest DECIMAL (10,2));
INSERT @ VALUES ('2015-12-15', 0, 1000.0), ('2016-06-15', 1250.0, 1000.0), ('2016-12-15', 10000.0, 1000.0);

SELECT DATEADD(MONTH, n.number, Cashflow_Date) Dates
     , MAX(Principal) / ISNULL(DATEDIFF(MONTH, Cashflow_Date, nextDate), 1) Principal
     , MAX(Interest) / ISNULL(DATEDIFF(MONTH, Cashflow_Date, nextDate), 1) Interest
FROM (
    SELECT t.Cashflow_Date
         , t.Principal
         , t.Interest
         , X.nextDate
    FROM @ t
    OUTER APPLY (
        SELECT MIN(Cashflow_Date)
        FROM @
        WHERE Cashflow_Date > t.Cashflow_Date) X(nextDate)) t
CROSS JOIN (
    SELECT number
    FROM master..spt_values
    WHERE type='P') n
WHERE n.number < ISNULL(DATEDIFF(MONTH, Cashflow_Date, nextDate), 1)
GROUP BY DATEADD(MONTH, n.number, Cashflow_Date), nextDate, Cashflow_Date
ORDER BY DATEADD(MONTH, n.number, Cashflow_Date);

您需要某种计数表来填写第一个日期和下一个日期之间的日期,然后您只需要根据第一个日期和下一个日期之间的月数来平均本金和利息。

答案 1 :(得分:0)

看看这是否有助于您开始摆脱游标

(未针对所有情况进行测试)

/*
one time setup

CREATE TABLE [dbo].[Tbl]
(
    [cf] [date] NOT NULL,
    [pmt] [int] NOT NULL,
    [intrest] [int] NOT NULL
) 
GO

insert into dbo.Tbl values ( '2015-12-15', 0 , 1000)
insert into dbo.Tbl values ( '2015-06-15', 0 , 1000)
insert into dbo.Tbl values ( '2016-12-15', 1000 , 1000)

*/


select Top 13 b.* , intrest/6.0 as int_mnthly, DATEADD(Month,Mnth, cf) as cf_mnthly
from dbo.Tbl b
cross join 
( 
    select 1 as Mnth Union ALL
    select 2 as Mnth Union ALL
    select 3 as Mnth Union ALL
    select 4 as Mnth Union ALL
    select 5 as Mnth Union ALL
    select 6 as Mnth 
) a
order by cf_mnthly