Na semana passada, um dos meus colegas me pediu para ajudá-lo a escrever uma consulta para preencher as datas ausentes na saída da consulta. Me deparei com algumas soluções, nenhuma me pareceu conveniente. Então, eu compilei meu próprio usando CTE recursiva ou Expressão de Tabela Comum.
Declaração do problema
Digamos que temos uma tabela que contém registros de chamadas recebidas de um atendimento ao cliente de 1 a 10 de junho de 2021. Em alguns dias, não há registro de chamadas. Se executarmos a instrução GROUP BY na coluna datetime, alguns dias estarão ausentes. A saída desejada é, datas ausentes terão valor 0. A saída de amostra estará abaixo:
Inquerir
SELECT CONVERT(varchar(10),B.call_time,111) AS OriginalDate, COUNT(*) as total
FROM Test1 B
GROUP BY CONVERT(varchar(10),B.call_time,111)
ORDER BY CONVERT(varchar(10),B.call_time,111)
Saída de Amostra
Saída Desejada
Minha abordagem para a solução
Em vez de usar a consulta GROUP BY simples, CTE e SUB QUERY são usados. O CTE recursivo é usado para gerar o intervalo de datas e LEFT OUTER JOIN é usado para combinar o valor com a data. Vamos explicar passo a passo.
CTE/Expressão de tabela comum
CTE ou Expressão de Tabela Comum especifica um conjunto de resultados nomeado temporário que é derivado de uma consulta simples e definido dentro do escopo de execução de uma única instrução SELECT/INSERT/UPDATE/DELETE/MERGE/CREATE VIEW. Ele também pode se referir a si mesmo, o que é chamado de CTE recursivo.
Preparando dados
-- Create the table
CREATE TABLE Test1(
call_time datetime,
name varchar(10) default ('Mehedi')
)
GO
-- Populate with sample data
INSERT INTO Test1 (call_time, name)
VALUES ('2021-06-01 08:00','A')
,('2021-06-01 09:05','C')
,('2021-06-01 12:50','E')
,('2021-06-01 16:17','D')
,('2021-06-01 18:53','G')
,('2021-06-03 11:07','F')
,('2021-06-03 13:09','A')
,('2021-06-03 16:26','E')
,('2021-06-03 19:56','C')
,('2021-06-03 21:24','A')
,('2021-06-04 19:13','A')
,('2021-06-04 11:45','B')
,('2021-06-04 15:02','C')
,('2021-06-08 23:02','A')
,('2021-06-09 03:04','E')
Crie a consulta
Primeiro, escreveremos um CTE que gerará todas as datas dentro do intervalo de datas.
DECLARE @StartDate DATE, @EndDate DATE
SET @StartDate = '2021-11-01'
SET @EndDate = '2021-11-08'
;WITH cte AS
( SELECT @StartDate AS sDate
UNION ALL
SELECT DATEADD(DAY,1,sDate)
FROM cte
WHERE sDate < @EndDate
)
SELECT sDate
FROM cte;
Agora esse CTE será refatorado para fazer uma subconsulta com LEFT OUTER JOIN para que a data que não tem o valor apareça e contenha o valor 0.
DECLARE @startdate DATETIME = '2021-06-01'
DECLARE @endDate DATETIME = '2021-06-10'
;WITH cte
AS
(
SELECT @startdate as sDate
UNION All
SELECT DATEADD(day,1,sDate) From cte where DATEADD(day,1,sDate) <= @endDate
)
SELECT
C.OriginalDate
,C.total
FROM
(
SELECT CONVERT(varchar(10),A.sDate,111) AS OriginalDate, COUNT(B.call_time) as total
FROM cte A
LEFT OUTER JOIN Test1 B
ON A.sDate = CONVERT(varchar(10),B.call_time,111)
GROUP by CONVERT(varchar(10),A.sDate,111)
) C
ORDER BY C.OriginalDate
Resultado final
Conclusão
Espero que seja útil para você. Feliz TSQL!
Também está disponível no meu blog pessoal!