The calendar solution mentioned in Hart CO's answer is always my go-to solution for this, but I'll add that you can create your own "calendar table" on the fly using recursive CTEs
This answer is slightly different to the other ones because it shows that you don't need to recurse over the initial table -- which makes this a more "copy-and-paste"-able solution
I would still recommend using a dedicated calendar table in your database in the vast majority of cases
The "calendar table" CTE
In SQL Server, you don't have to include FROM
in your queries, so you can spin up a "calendar table" pretty quickly between any dates that you want (almost, more details below):
WITH dates AS (
SELECT CAST('2014-01-01' AS DATE) AS date_axis
UNION ALL
SELECT DATEADD(DAY, 1, date_axis)
FROM dates
WHERE date_axis < '2015-01-01'
)
SELECT *
FROM dates
OPTION(MAXRECURSION 500)
;
This creates a table with a single column, date_axis
, and a row for every day between 2014-01-01 and 2015-01-01, inclusive
I've hard-coded 2014-01-01 and 2015-01-01, but you could use variants of this to work with whatever you need -- such as passing in values at runtime (if the query is run via a BI tool or script), or by building relatively off of the current date (if you only need a relative range):
WITH dates AS (
SELECT DATEADD(DAY, -365, CAST(GETDATE() AS DATE)) AS date_axis
UNION ALL
SELECT DATEADD(DAY, 1, date_axis)
FROM dates
WHERE date_axis < CAST(GETDATE() AS DATE)
)
SELECT *
FROM dates
OPTION(MAXRECURSION 500)
;
The OPTION(MAXRECURSION 500)
is SQL Server syntax for setting up how many iterations you can do in the recursive CTE. Since each loop corresponds to adding a day, using OPTION(MAXRECURSION 500)
would error if you needed more than 500 days (the default is 100, by the way)
The max you can set this to is 32767
which is just under 90 years -- if you need more days than this, you should definitely consider creating a physical calendar table instead 😝
Answering the question
To answer this question, another option for setting the bounds for the recursive CTE are to use some variables (in databases that support them) or any other supported mechanism to pull minimum and maximum bounds:
DECLARE @MINDATE DATE = (SELECT MIN("start") FROM example);
DECLARE @MAXDATE DATE = (SELECT MAX("end") FROM example);
WITH dates AS (
SELECT @MINDATE AS date_axis
UNION ALL
SELECT DATEADD(DAY, 1, date_axis)
FROM dates
WHERE date_axis < @MAXDATE
)
SELECT *
FROM dates
OPTION(MAXRECURSION 500)
;
Note that Pரதீப் is right when they say that overflowed's answer won't work because of aggregates in the (sub-queries of the) recursive CTE -- at least, for SQL Server it isn't allowed, so the variables approach would be more correct for the OPs database
The last part is then just joining the original table back onto the "calendar table" to get the output:
DECLARE @MINDATE DATE = (SELECT MIN("start") FROM example);
DECLARE @MAXDATE DATE = (SELECT MAX("end") FROM example);
WITH dates AS (
SELECT @MINDATE AS date_axis
UNION ALL
SELECT DATEADD(DAY, 1, date_axis)
FROM dates
WHERE date_axis < @MAXDATE
)
SELECT
"name",
dates.date_axis AS "start",
dates.date_axis AS "end"
FROM dates
INNER JOIN example
ON dates.date_axis BETWEEN example."start" AND example."end"
OPTION(MAXRECURSION 32767)
;
This will now work for any number of rows in the original table and so I've whacked up the max recursion option to allow for a wide range of dates (but you might want to set a more sensible limit, if you go this route)
The full db<>fiddle for this is available at:
START
andEND
fields in your output identical? – Bowfin