Reputation: 9021
I'm messing about with a test database table structure to store events with recurrence. I have two tables:
Course
Id = 1
Title = Test Course
CourseMeta
Id = 1
CourseId = 1
StartDate = 2018-01-01
RepeatEvery = 7
RepeatAmount = 4
Assuming the values above, what I'm trying to produce (in individual SQL rows) is a list of courses for each date in the range, starting at 2018-01-01 and occurring every 7 days, until there have been 4 iterations. For example, I'm after this output:
Title Date
----------- ----------
Test Course 2018-01-01
Test Course 2018-01-08
Test Course 2018-01-15
Test Course 2018-01-22
I'm stuck because I've no idea how to get MS SQL (2012) to show a row multiple times based on a condition. I did have a search and found some information, but nothing which helped so far. Not even sure if this is the best way to store this information.
Upvotes: 0
Views: 40
Reputation: 272006
If you have a table of numbers you can do this (uses master..spt_values
as the table of numbers):
WITH course(id, title) AS (
SELECT 1, 'test course'
), coursemeta(courseid , startdate, repeatevery, repeatamount) AS (
SELECT 1, '2018-01-01', 7, 4
), numbers(number) AS (
SELECT number FROM master..spt_values WHERE type = 'p'
)
SELECT id, title, DATEADD(day, numbers.number * repeatevery, startdate)
FROM course
INNER JOIN coursemeta ON course.id = coursemeta.courseid
INNER JOIN numbers ON numbers.number < coursemeta.repeatamount
Result:
| id | title | (No column name) |
|----|-------------|-------------------------|
| 1 | test course | 2018-01-01 00:00:00.000 |
| 1 | test course | 2018-01-08 00:00:00.000 |
| 1 | test course | 2018-01-15 00:00:00.000 |
| 1 | test course | 2018-01-22 00:00:00.000 |
Upvotes: 1
Reputation: 1269445
You can use a recursive CTE to generate the rows:
with cte as (
select courseid, startdate, repeatevery, repeatamount, 1 as cnt
from coursemeta
union all
select courseid, dateadd(day, repeatevery, startdate), repeatevery, repeatamount, cnt + 1
from cte
where cnt < repeatamount
)
select courseid, startdate
from cte;
To get the name, you would add a final JOIN
.
Note: If repeatamount
exceeds 100, add with option (maxrecursion 0)
.
Upvotes: 1