SQL Fiddle
CTE_Users
nos dá uma lista de todos os usuários com datas de início e término para cada usuário. Ele é associado ao
Calendar
tabela para gerar linha para cada data para cada usuário. Finalmente, é deixado junto com a tabela principal
Test
para retornar Total
para cada data. ISNULL
garante que as datas que não possuem dados retornem 0. WITH
CTE_Users
AS
(
SELECT
Userid
,MIN(startdate) AS StartDate
,MAX(enddate) AS EndDate
FROM TEST
GROUP BY Userid
)
SELECT
ROW_NUMBER() OVER (ORDER BY CTE_Users.Userid, Calendar.dt) AS ID
,CTE_Users.Userid
,T.Id1
,Calendar.dt
,ISNULL(T.Total, 0) AS Total
FROM
CTE_Users
INNER JOIN Calendar ON
Calendar.dt >= CTE_Users.StartDate
AND Calendar.dt <= CTE_Users.EndDate
LEFT JOIN TEST AS T ON
T.Userid = CTE_Users.Userid
AND T.date1 = Calendar.dt
ORDER BY CTE_Users.Userid, Calendar.dt;
Resultado
| ID | Userid | Id1 | dt | Total |
|----|--------|--------|------------|-------|
| 1 | abc | 1 | 2015-01-13 | 200 |
| 2 | abc | 2 | 2015-01-14 | 200 |
| 3 | abc | 3 | 2015-01-15 | 200 |
| 4 | abc | (null) | 2015-01-16 | 0 |
| 5 | abc | (null) | 2015-01-17 | 0 |
| 6 | abc | (null) | 2015-01-18 | 0 |
| 7 | abc | 4 | 2015-01-19 | 200 |
| 8 | abc | 5 | 2015-01-20 | 200 |
| 9 | abc | (null) | 2015-01-21 | 0 |
| 10 | abc | (null) | 2015-01-22 | 0 |
| 11 | abc | 6 | 2015-01-23 | 200 |
| 12 | abc | 7 | 2015-01-24 | 200 |
| 13 | def | (null) | 2015-02-10 | 0 |
| 14 | def | (null) | 2015-02-11 | 0 |
| 15 | def | 8 | 2015-02-12 | 200 |
| 16 | def | 9 | 2015-02-13 | 200 |
| 17 | def | (null) | 2015-02-14 | 0 |
| 18 | def | 10 | 2015-02-15 | 200 |
| 19 | def | 11 | 2015-02-16 | 200 |
| 20 | def | 12 | 2015-02-17 | 200 |
| 21 | def | 13 | 2015-02-18 | 200 |
| 22 | def | (null) | 2015-02-19 | 0 |
| 23 | def | (null) | 2015-02-20 | 0 |
ID
é um número de linha gerado dinamicamente.Id1
são os IDs originais do Test
tabela. Eu geraria
Calendar
mesa assim:CREATE TABLE [Calendar](
[dt] [date] NOT NULL
CONSTRAINT [PK_Calendar] PRIMARY KEY CLUSTERED
(
[dt] ASC
));
-- 10K dates from 2000-01-01 till 2027-05-18
INSERT INTO Calendar (dt)
SELECT TOP (10000)
DATEADD(day, ROW_NUMBER() OVER (ORDER BY s1.[object_id])-1, '2000-01-01') AS dt
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
OPTION (MAXDOP 1);