计算多种利率的利息

2024-02-24

我有一个存储利率的表,每个利率都有一个适用的开始日期。表中较晚的条目将取代较早的条目。我必须使用开始日期、结束日期和金额查询该表。根据这些值,我需要最终得到一个考虑了日期范围内不同利率的总利息金额。

CREATE TABLE [dbo].[Interest_Rates](
[Interest_Rate] [float] NULL,
[Incept_Date] [datetime] NULL
) ON [PRIMARY]
GO

我有四个利率“区间”:

INSERT [dbo].[Interest_Rates] ([Interest_Rate], [Incept_Date]) VALUES (10, CAST(N'2001-05-03 11:12:16.000' AS DateTime))
GO
INSERT [dbo].[Interest_Rates] ([Interest_Rate], [Incept_Date]) VALUES (11.5, CAST(N'2014-01-07 10:49:28.433' AS DateTime))
GO
INSERT [dbo].[Interest_Rates] ([Interest_Rate], [Incept_Date]) VALUES (13.5, CAST(N'2016-03-01 00:00:00.000' AS DateTime))
GO
INSERT [dbo].[Interest_Rates] ([Interest_Rate], [Incept_Date]) VALUES (15.5, CAST(N'2016-05-01 00:00:00.000' AS DateTime))
GO

我想知道的是,是否可以计算一段时间的利率,从利率为 11.5% 时开始,到利率上升两倍至 11.5% 时结束。 13.5%,在单个查询中。

似乎每个“频段”的利息计算都可以使用精彩的功能来完成苏普罗丁·阿加瓦尔的例子如下:

DECLARE @StartDate DateTime
DECLARE @EndDate DateTime
DECLARE @Amount Float

SET @StartDate = '2014-04-22'
SET @EndDate = '2016-04-13'
SET @Amount = 150000.00

SELECT
@Amount*(POWER(1.1550, CONVERT(NUMERIC(8,3),
DATEDIFF(d, @StartDate, @EndDate)/365.25))) - @Amount
as TotalInterest

(上例中的利率为 15.5%)

我陷入困境的是如何将计算与利率表相互关联,以便连接考虑到日期范围的每个小部分属于哪个“范围”。

任何帮助或建议将不胜感激。


tl;dr:完成的查询是这个长解释末尾的最后一个代码块。

让我们逐步完成这一过程,然后将最终解决方案作为一个查询呈现。需要采取几个步骤来解决这个问题。

1) 找出我们所需的日期范围涵盖哪些费率

2)设计一种巧妙的方法来选择这些费率

3) 将这些日期和利率结合起来,得出应计利息总额。


一些初步说明

由于您的利率计算示例将天数视为其最佳分辨率,因此我只使用数据类型date代替datetime。如果您需要更精细的分辨率,请告诉我,我可以更新。

我正在使用以下声明的变量

declare @EndOfTime date = '2049-12-31' -- This is some arbitrary end of time value that I chose
declare @StartDate Date = '2012-04-22' -- I made this earlier to cover more rates
declare @EndDate Date = '2016-04-13'
declare @Amount Float = 100000.00 -- I changed it to a softer number



1) 日期间隔

现在,您的interest_rates 表列出了如下日期:

+ ------------- + ----------- +
| interest_rate | incept_date |
+ ------------- + ----------- +
| 10            | 2001-05-03  |
| 11.5          | 2014-01-07  |
| 13.5          | 2016-03-01  |
| 15.5          | 2016-05-01  |
+ ------------- + ----------- +

但你希望它列出这样的间隔:

+ ------------- + ------------ + ------------ +
| interest_rate | inter_begin  | inter_end    |
+ ------------- + ------------ + ------------ +
| 10            | 2001-05-03   | 2014-01-06   |
| 11.5          | 2014-01-07   | 2016-02-29   |
| 13.5          | 2016-03-01   | 2016-04-30   |
| 15.5          | 2016-05-01   | 2049-12-31   |
+ ------------- + ------------ + ------------ +

以下查询可以将日期列表转换为间隔:

select    i1.interest_rate
        , i1.incept_date as inter_begin
        , isnull(min(i2.incept_date) - 1,@EndOfTime) as inter_end
    from #interest i1
    left join #interest i2 on i2.incept_date > i1.incept_date
    group by i1.interest_rate, i1.incept_date

注意:我在这里对日期算术有点松散,没有使用 dateadd() 命令。

像这样跟踪日期间隔可以使选择适用的费率变得更加容易。

2) 选择费率

现在,我们可以使用上述查询作为 CTE 来选择位于所需范围内的记录。这个查询有点棘手,所以需要一些时间来真正理解它。

; with
    intervals as ( 
        -- The above query/table
    )
select  *
    from intervals
    where inter_begin >= (
        select inter_begin -- selects the first rate covered by our desired interval
            from intervals
            where @StartDate between inter_begin and inter_end
    )
        and inter_end <= (
            select inter_end -- selects the last rate covered by our desired interval
                from intervals
                where @EndDate between inter_begin and inter_end
    )

这有效地过滤掉了我们不关心的任何费率,并为我们留下了

+ ------------- + ------------ + ------------ +
| interest_rate | inter_begin  | inter_end    |
+ ------------- + ------------ + ------------ +
| 10            | 2001-05-03   | 2014-01-06   |
| 11.5          | 2014-01-07   | 2016-02-29   |
| 13.5          | 2016-03-01   | 2016-04-30   |
+ ------------- + ------------ + ------------ +

3)计算利息

现在我们已经拥有了所需的一切,计算利息只需从该表中选择正确的内容即可。您为计算所写的大部分内容保持不变;主要更改在 datediff() 命令中。使用@开始日期 and @EndDate不会向我们提供按每个特定费率花费的天数的准确计数。我们通过使用遇到了同样的问题中间开始 and 中间结束。相反,我们必须使用 case 语句,例如

datediff(day, 
    case when @StartDate > inter_begin then @StartDate else inter_begin end,
    case when @EndDate < inter_end then @EndDate else inter_end end
)

将其放入上面的查询中即可得到

; with
    intervals as (...) -- same as above
select  *
        , DATEDIFF(day,
              case when @StartDate > inter_begin then @StartDate else inter_begin end,
              case when @EndDate < inter_end then @EndDate else inter_end end) as days_active
        , @Amount*(POWER((1+interest_rate/100),
              convert(float,
                  DATEDIFF(day,
                      case when @StartDate > inter_begin then @StartDate else inter_begin end,
                      case when @EndDate < inter_end then @EndDate else inter_end end
                  )
              )/365.25)
          ) - @Amount as Actual_Interest
    from ... -- same as above

这给了我们这张表

+ ------------- + ------------ + ------------ + ----------- + --------------- +
| interest_rate | inter_begin  | inter_end    | days_active | Actual_interest |
+ ------------- + ------------ + ------------ + ----------- + --------------- +
| 10            | 2001-05-03   | 2014-01-06   | 624         | 17683.63        |
| 11.5          | 2014-01-07   | 2016-02-29   | 786         | 26283.00        |
| 13.5          | 2016-03-01   | 2016-04-30   | 43          | 1501.98         |
+ ------------- + ------------ + ------------ + ----------- + --------------- +

最后,将其放入 CTE 中并求和实际利息 field:

declare @EndOfTime date = '2049-12-31' -- This is some arbitrary end of time value that I chose
declare @StartDate Date = '2012-04-22' -- I made this earlier to cover more rates
declare @EndDate Date = '2016-04-13'
declare @Amount Float = 100000.00 -- I changed it to a softer number

; with
    intervals as (
        select    i1.interest_rate
                , i1.incept_date as inter_begin
                , isnull(min(i2.incept_date) - 1,@EndOfTime) as inter_end
            from #interest i1
            left join #interest i2 on i2.incept_date > i1.incept_date
            group by i1.interest_rate, i1.incept_date
    )
    , interest as (
        select  *
                , DATEDIFF(day,
                      case when @StartDate > inter_begin then @StartDate else inter_begin end,
                      case when @EndDate < inter_end then @EndDate else inter_end end) as days_active
                , @Amount*(POWER((1+interest_rate/100),
                      convert(float,
                          DATEDIFF(day,
                              case when @StartDate > inter_begin then @StartDate else inter_begin end,
                              case when @EndDate < inter_end then @EndDate else inter_end end
                          )
                      )/365.25)
                  ) - @Amount as Actual_Interest
            from intervals
            where inter_begin >= (
                select inter_begin -- selects the first rate covered by our desired interval
                    from intervals
                    where @StartDate between inter_begin and inter_end
            )
                and inter_end <= (
                    select inter_end -- selects the last rate covered by our desired interval
                        from intervals
                        where @EndDate between inter_begin and inter_end
            )
    )
select sum(actual_interest) as total_interest
    from interest
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

计算多种利率的利息 的相关文章

随机推荐

  • Scalac 挂在 RegexParser 的阶段类型上

    我有一个 scala 程序 其中有一个解析器组合器 这是通过扩展来完成的scala util parsing combinator RegexParsers 我使用 Scala 2 10 开发它 一切正常 昨天我将系统升级到了 Scala
  • 播放前检测浏览器/设备是否可以内嵌播放 HTML5 视频

    我知道我可以检查一下navigator userAgent如果设备是 iPhone 但还有其他设备 其中一些我不知道哪些设备会在其自己的播放器中播放视频 可以列出所有不内联播放视频的浏览器 设备 但我想知道是否还有其他解决方案 JavaSc
  • 创建 iOS 应用程序 (Xcode) 时,如何关闭自动图标“凝胶”

    有没有办法去掉创建 iPhone 应用程序时自动添加到图标的突出显示 或者我必须在 PS 中手动补偿 Thanks Set UIPrerenderedIcon to YES在你的 Info plist 中 欲了解更多信息 请参阅 信息属性列
  • 将 pandas 数据框中的 datetime64 列拆分为日期和时间列

    如果我有一个数据框 第一列是 datetime64 列 如何将此列拆分为 2 个新列 日期列和时间列 这是到目前为止我的数据和代码 DateTime Actual Consensus Previous 20140110 13 30 00 7
  • R 如何将“-17+3”等简单函数分离为数字,例如“-17”和“3”

    我的数据就像 17 3 2 6 我需要做的是将每个数字分成两个数字 例如 17 3 变为 17 和 3 2 6 分为 2 和 6 通过使用 R 非常感谢 gregexpr http stat ethz ch R manual R devel
  • Fortran:哪种方法可以更快地更改数组的等级? (重塑与指针)

    当我们处理大型数组时 考虑数组的等级和形状变化的成本可能很重要 特别是当它在多个子例程 函数中发生几次时 我问题的主要目的是将数组的排名从第二更改为第一 反之亦然 为此 可以使用 重塑声明 指针变量 下面的代码展示了如何使用指针变量 pro
  • C++中双冒号的全名

    如果我有课 class A public A void print private int value A A value 0 void A print cout lt lt value lt lt endl 最后两行中 符号的完整名称是什
  • 如何使用messagebox输出调试信息

    我正在使用 MessageBox 尝试进行一些手动调试 这就是我所想出的全部 我应该如何使其工作 private void DisplayMessageBoxText MessageBox Show Alert Message 您可以使用写
  • 关于使用遗留代码的建议

    我需要一些关于如何使用遗留代码的建议 不久前 我接到的任务是向报告应用程序添加一些报告 2005 年用 Struts 1 编写的 没什么大不了的 但是代码相当混乱 没有使用Action形式 基本上代码就是一个巨大的action 里面有很多i
  • Dockerfile 中的 Mongorestore

    我想创建一个启动 mongo 服务器并自动从以前的版本恢复的 Docker 映像mongodump启动时 这是我的图像 Dockerfile FROM mongo COPY dump home dump CMD mongorestore h
  • 无法删除 Qt 布局的子布局中的小部件

    我正在使用 Windows 版 Qt 5 5 0 在用于登录和注册的对话框中 我使用 QVBoxLayout 作为对话框的主布局 并将 QGridLayout 添加到 mainLayout 当我单击 注册 按钮时 它将添加太多用于注册的 L
  • 使用 ghc 编译 Haskell 代码时出现专业化警告

    尝试编译时出现以下错误 ghc make O2 Wall fforce recomp 1 of 1 编译主程序 isPrimeSmart hs isPrimeSmart o 规格构造 函数 wa v s2we lid 有两种调用模式 但限制
  • Ngrok:如何打开80端口

    我刚刚在本地计算机上安装了 ngrok 运行 ngrok http 80 照常 但是当我尝试访问80端口时 localhost 80 我收到此错误消息 与 http ngrok io 的连接已成功通过隧道连接到 您的 ngrok 客户端 但
  • 管道成功完成后 Bitbucket Webhook 触发

    我想在管道成功完成后触发 Webhook 我查看了触发器列表 但没有找到任何内容 是否有解决方法可以通过 Pipeliens 手动触发 Webhook 您可以使用构建状态已更新 https confluence atlassian com
  • 核心数据:观察某种类型实体的所有变化

    每当添加 更改 删除某种类型的实体时 我希望收到通知 我知道通过向managedObjectContext 但随后我必须搜索返回的三个集合以查看它们是否包含该类型的对象 我可以用filteredSetUsingPredicate 但是每次有
  • 无法理解 PcapNG 文件中的 802.11 数据帧格式

    I have PcapNG由 Wireshark 创建的文件 我尝试用它来解析python pcapng However I cannot figure out how to reconcile the output I receive f
  • 按下控制器时,UIBarButtonItemStyleDone 不会在导航栏中创建蓝色按钮

    我在几个不同的论坛上搜索过 似乎找不到这个问题的答案 我已将一个栏按钮项目添加到导航控制器并将其样式设置为 UIBarButtonItemStyleDone 当这是导航堆栈上的第一个控制器时 该按钮正确显示为蓝色 但是 当创建控制器并将其推
  • 派系问题算法设计

    我的算法课上的作业之一是设计一种穷举搜索算法来解决派系问题 也就是说 给定尺寸图n 该算法应该确定是否存在尺寸的完整子图k 我想我已经得到了答案 但我忍不住认为它可以改进 这是我所拥有的 版本1 input 由数组 A 0 表示的图n 1
  • React router dom v6 不会重定向到未找到

    所以我刚刚从react router domv5 到 v6 我认为 exact不再存在 因为它被省略了 但就我而言 它不起作用 如果找不到路由 则应重定向到not found页面 但无法弄清楚为什么它不起作用 它只是打印了一张白页 所以 这
  • 计算多种利率的利息

    我有一个存储利率的表 每个利率都有一个适用的开始日期 表中较晚的条目将取代较早的条目 我必须使用开始日期 结束日期和金额查询该表 根据这些值 我需要最终得到一个考虑了日期范围内不同利率的总利息金额 CREATE TABLE dbo Inte