Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Remplir les dates manquantes pour la sortie de la requête SQL Server à l'aide de CTE

La semaine dernière, un de mes collègues m'a demandé de l'aider à écrire une requête pour remplir les dates manquantes dans la sortie de la requête. Je suis tombé sur quelques solutions, aucune ne me semblait pratique. J'ai donc compilé le mien en utilisant CTE récursif ou Common Table Expression.

Énoncé du problème

Supposons que nous ayons un tableau contenant les enregistrements d'appels entrants d'un service client du 1er au 10 juin 2021. Certains jours, il n'y a aucun enregistrement d'appel. Si nous exécutons l'instruction GROUP BY sur la colonne datetime, certains jours seront manquants. La sortie souhaitée est que les dates manquantes auront la valeur 0. Un exemple de sortie sera ci-dessous :

Requête

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)

Exemple de sortie

Sortie souhaitée

Mon approche de la solution

Plutôt que d'utiliser une simple requête GROUP BY, CTE et SUB QUERY sont utilisés. CTE récursif est utilisé pour générer la plage de dates et LEFT OUTER JOIN est utilisé pour combiner la valeur avec la date. Expliquons étape par étape.

CTE/Expression de table commune

CTE ou Common Table Expression spécifie un jeu de résultats nommé temporaire dérivé d'une requête simple et défini dans la portée d'exécution d'une seule instruction SELECT/INSERT/UPDATE/DELETE/MERGE/CREATE VIEW. Il peut également se référer à lui-même, ce qui est appelé CTE récursif.

Préparation des données

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

Créer la requête

Tout d'abord, nous allons écrire un CTE qui générera toutes les dates dans la plage de dates.

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;

Maintenant, ce CTE sera refactorisé pour faire une sous-requête avec LEFT OUTER JOIN afin que la date qui n'a pas la valeur apparaisse et contienne la valeur 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

Résultat final

Conclusion

J'espère que cela vous sera utile. Joyeux TSQL !

Il est également disponible sur mon blog personnel !