There is no need for loops, cursors or recursive CTEs... It's as easy as the following.
WITH
cte_n1 (n) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (n)), -- 10
cte_n2 (n) AS (SELECT 1 FROM cte_n1 a CROSS JOIN cte_n1 b), -- 100
cte_Calendar (dt) AS (
SELECT TOP (DATEDIFF(DAY, '2012-01-01', '2020-12-31') + 1)
CONVERT(DATE, DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1, '2012-01-01'))
FROM
cte_n2 a CROSS JOIN cte_n2 b -- 10,000
)
SELECT
ID = DATEDIFF(DAY, '2012-01-01', c.dt) + 1,
[Year] = YEAR(c.dt),
[Month] = MONTH(c.dt),
[Day] = DAY(c.dt)
FROM
cte_Calendar c;
GO
Or you can use it to populate a permanent table...
IF OBJECT_ID('tempdb.dbo.YMD', 'U') IS NOT NULL
BEGIN DROP TABLE tempdb.dbo.YMD; END;
GO
CREATE TABLE tempdb.dbo.YMD (
ID int NOT NULL IDENTITY(1,1)
CONSTRAINT pk_YMD PRIMARY KEY CLUSTERED (ID),
[Year] int NOT NULL,
[Month] tinyint NOT NULL,
[Day] tinyint NOT NULL
);
GO
--------------------------------------------------------------------------------------------------------
WITH
cte_n1 (n) AS (SELECT 1 FROM (VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1)) n (n)), -- 10
cte_n2 (n) AS (SELECT 1 FROM cte_n1 a CROSS JOIN cte_n1 b), -- 100
cte_Calendar (dt) AS (
SELECT TOP (DATEDIFF(DAY, '2012-01-01', '2020-12-31') + 1)
CONVERT(DATE, DATEADD(DAY, ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) - 1, '2012-01-01'))
FROM
cte_n2 a CROSS JOIN cte_n2 b -- 10,000
)
INSERT tempdb.dbo.YMD (Year, Month, Day)
SELECT
[Year] = YEAR(c.dt),
[Month] = MONTH(c.dt),
[Day] = DAY(c.dt)
FROM
cte_Calendar c;
GO
------------------------------------------------------------------------------------------------------
SELECT
YMD.ID,
YMD.Year,
YMD.Month,
YMD.Day
FROM
tempdb.dbo.YMD;
GO