sql - T-SQL 根据单个即将到来的日期和续订期限生成续订日期列表

标签 sql sql-server tsql

我的任务是创建一份报告,根据单个续订日期和续订期限显示每个帐户包的续订日期。此报告应显示截至 2018 年 12 月底的所有续订日期。

所有帐户包都有以月为单位的期限(1 到 12)和当前续订日期(下一个即将到来)(AccountPackage 表)。

+--------------+---------------+--------------+
| AccountPkgID | PkgTermMonths | RenewalDate  |
+--------------+---------------+--------------+
|            1 |             1 | 12/1/2015    |
|            2 |             3 | 12/1/2015    |
|            3 |             6 | 12/1/2015    |
|            4 |            12 | 12/1/2015    |
+--------------+---------------+--------------+

我能够通过使用所有月份的表格(Report_MonthlyDates 表)对包裹表进行笛卡尔积来处理所有每月的包裹。

+----------------+
| dtfirstofmonth |
+----------------+
| 12/1/2015      |
| 1/1/2016       |
| 2/1/2016       |
| 3/1/2016       |
| . each month . |
| 12/1/2018      |
+----------------+

下面是我想出的 SQL,它仅适用于 1 个月的包……3 个月或更长的包不起作用。

SELECT AllPkgs.AccountPkgID, AllPkgs.PkgTermMonths, MonthlyPkgs.dtfirstofmonth
from
(SELECT AccountPkgID,  PkgTermMonths, RenewalDate
FROM Accountpackage 
WHERE RenewalDate >= '12/1/2015' 
AND RenewalDate < '1/1/2019') AllPkgs
INNER JOIN 
(SELECT dtfirstofmonth 
FROM [Report_MonthlyDates] 
WHERE dtfirstofmonth >= '12/1/2015' 
AND dtfirstofmonth < '1/1/2019') MonthlyPkgs ON (AllPkgs.months = 1)

我想到的唯一的另一个想法是光标,但它的性能会很糟糕。我希望能够使用表函数或其他函数来完成此操作。

我想要得到的输出:

+--------------+-----------------+
| AccountPkgID |  RenewalDate    |
+--------------+-----------------+
|            1 | 12/1/2015       |
|            1 | 1/1/2016        |
|            1 | … every month … |
|            1 | 12/1/2018       |
|            2 | 12/1/2015       |
|            2 | 3/1/2016        |
|            2 | 6/1/2016        |
|            2 | 9/1/2016        |
|            2 | 12/1/2016       |
|            2 | 3/1/2017        |
|            2 | 6/1/2017        |
|            2 | 9/1/2017        |
|            2 | 12/1/2017       |
|            2 | 3/1/2018        |
|            2 | 6/1/2018        |
|            2 | 9/1/2018        |
|            2 | 12/1/2018       |
|            3 | 12/1/2015       |
|            3 | 6/1/2016        |
|            3 | 12/1/2016       |
|            3 | 6/1/2017        |
|            3 | 12/1/2017       |
|            3 | 6/1/2018        |
|            3 | 12/1/2018       |
|            4 | 12/1/2015       |
|            4 | 12/1/2016       |
|            4 | 12/1/2017       |
|            4 | 12/1/2018       |
+--------------+-----------------+

任何想法都会有很大的帮助。

最佳答案

您似乎需要一个数字表。一旦我们构建了它,剩下的只是一些 SQL:

with numbers as (
      select n.*
      from (select row_number() over (order by (select null)) - 1 as n -- starts at 0
            from master..spt_values
           ) n
      where n < 100 -- 100 values should be quite sufficient for the end of 2018
     )
select ap.AccountPkgID,
       dateadd(month, n.n  * ap.PkgTermMonths, ap.renewaldate) as renewaldate
from AccountPackage ap join
     numbers n
     on dateadd(month, n.n * ap.PkgTermMonths, ap.renewaldate) <= '2018-12-31'
order by AccountPkgID, n.n;

关于sql - T-SQL 根据单个即将到来的日期和续订期限生成续订日期列表,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33711972/

相关文章:

SQL 将日期转换为工作日名称

sql - 数据库查询,给出意想不到的结果

sql - 期望从 SQL 中的 XML.value() 返回 null,但得到 0

sql - SQL Server自增主键的上限

sql-server - SQL Server 2005 FREE TEXT() 性能问题

mysql - 查找两列中的不同值

sql-server - Mongodb 中的 Max 和 group by

sql-server - SQL Server 2008在创建新数据库时自动创建表

sql-server-2005 - 艰难的 T-SQL 左连接?

sql - 计算两点之间的距离(纬度,经度)