CTE_Users giver os en liste over alle brugere med start- og slutdatoer for hver bruger.
Den er forbundet med Calendar tabel for at generere række for hver dato for hver bruger.
Til sidst efterlades den sammen med hovedtabellen Test for at returnere Total for hver dato. ISNULL sikrer, at de datoer, der ikke har data, returnerer 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;
Resultat
| 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 er et rækkenummer genereret i farten.Id1 er originale id'er fra Test bord.
Jeg ville generere Calendar tabel som denne:
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);