T-SQL pour générer la list des dates de renouvellement en fonction de la date unique et de la date de renouvellement

J'ai été chargé de créer un rapport qui indiquera la date de renouvellement de chaque count en fonction d'une date de renouvellement unique et de la durée de renouvellement. Ce rapport devrait montrer toutes les dates de renouvellement jusqu'à la fin de décembre 2018.

Tous les packages de count ont un terme en mois (1 à 12) et la date de renouvellement en cours (le prochain suivant) (table AccountPackage).

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

J'ai été capable de gérer tous les packages mensuels en faisant un produit cartésien de la table de packages avec une table de tous les mois (table Report_MonthlyDates).

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

Voici le SQL que j'ai trouvé ci-dessous qui a fonctionné pour seulement des packages de 1 mois … le 3 mois ou plus ne fonctionnait pas.

 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) 

La seule autre idée que j'ai trouvé était un slider, mais il aura une performance horrible. J'aimerais pouvoir le faire avec une fonction de table ou quelque chose.

La sortie que j'aimerais get:

 +--------------+-----------------+ | 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 | +--------------+-----------------+ 

Toutes les idées seraient une aide énorme.

Vous semblez avoir besoin d'une table de nombres. Une fois que nous construisons cela, le rest est juste un peu de 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, nn * ap.PkgTermMonths, ap.renewaldate) as renewaldate from AccountPackage ap join numbers n on dateadd(month, nn * ap.PkgTermMonths, ap.renewaldate) <= '2018-12-31' order by AccountPkgID, nn;