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

时间:2015-11-14 18:44:12

标签: 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       |
+--------------+-----------------+

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

1 个答案:

答案 0 :(得分:2)

您似乎需要一个数字表。一旦我们构造了它,剩下的只是一些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;