Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

Como posso juntar meus dados a um calendário para obter um registro para cada dia do início ao fim no SQL Server


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);