SQL Server: How to select all days in a date range even if no data exists for some days

You can use a recursive CTE to build your list of 30 days, then join that to your data

--test
select cast('05 jan 2011' as datetime) as DT, 1 as val into #t
union all select CAST('05 jan 2011' as datetime), 1 
union all select CAST('29 jan 2011' as datetime), 1 

declare @start datetime = '01 jan 2011'
declare @end   datetime = dateadd(day, 29, @start)

;with amonth(day) as
(
    select @start as day
        union all
    select day + 1
        from amonth
        where day < @end
)
select amonth.day, count(val)
    from amonth 
    left join #t on #t.DT = amonth.day
group by amonth.day


>>

2011-01-04 00:00:00.000 0
2011-01-05 00:00:00.000 2
2011-01-06 00:00:00.000 0
2011-01-07 00:00:00.000 0
2011-01-08 00:00:00.000 0
2011-01-09 00:00:00.000 0
...

Using CTE:

WITH DateTable
AS
(
    SELECT CAST('20110101' AS Date) AS [DATE]
    UNION ALL
    SELECT DATEADD(dd, 1, [DATE])
    FROM DateTable
    WHERE DATEADD(dd, 1, [DATE]) < cast('20110201' as Date)
)
SELECT dt.[DATE], ISNULL(md.[COUNT], 0) as [COUNT]
FROM [DateTable] dt
LEFT JOIN [MyData] md
ON md.[DATE] = dt.[DATE]

This is assuming everything's a Date; if it's DateTime, you'll have to truncate (with DATEADD(dd, 0, DATEDIFF(dd, 0, [DATE]))).


@Alex K.'s answer is completely correct, but it doesn't work for versions that do not support Recursive common table expressions (like the version I'm working with). In this case the following would do the job.

DECLARE @StartDate datetime = '2015-01-01'
DECLARE @EndDate datetime = SYSDATETIME()

;WITH days AS
(
  SELECT DATEADD(DAY, n, DATEADD(DAY, DATEDIFF(DAY, 0, @StartDate), 0)) as d
    FROM ( SELECT TOP (DATEDIFF(DAY, @StartDate, @EndDate) + 1)
            n = ROW_NUMBER() OVER (ORDER BY [object_id]) - 1
           FROM sys.all_objects ORDER BY [object_id] ) AS n
)
select days.d, count(t.val)
    FROM days LEFT OUTER JOIN yourTable as t
    ON t.dateColumn >= days.d AND t.dateColumn < DATEADD(DAY, 1, days.d)
GROUP BY days.d
ORDER BY days.d;