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

Preencher datas ausentes para saída de consulta do SQL Server usando CTE


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!