sql >> Databasteknik >  >> RDS >> Sqlserver

Fyll i saknade datum för SQL Server Query Output med CTE

Förra veckan bad en av mina kollegor mig att hjälpa honom att skriva en fråga för att fylla i saknade datum i frågeutdata. Jag stötte på ett par lösningar, ingen av dem verkade bekväma för mig. Så jag kompilerade min egen med hjälp av rekursiv CTE eller Common Table Expression.

Problembeskrivning

Låt oss säga att vi har en tabell som innehåller inkommande samtalsuppgifter för en kundtjänst från 1:a till 10:e juni 2021. Vissa dagar finns det ingen samtalspost. Om vi ​​kör GROUP BY-satsen på kolumnen datetime, kommer några dagar att saknas. Önskad utdata är, saknade datum kommer att vara 0 värde. Exempelutdata kommer att vara nedan:

Fråga

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)

Exempelutdata

Önskad utdata

Mitt tillvägagångssätt till lösning

Istället för att använda enkel GROUP BY-fråga används CTE och SUB QUERY. Rekursiv CTE används för att generera datumintervallet och LEFT OUTER JOIN används för att kombinera värdet med datumet. Låt oss förklara steg för steg.

CTE/Common Table Expression

CTE eller Common Table Expression specificerar en temporär namngiven resultatuppsättning som härleds från en enkel fråga och definieras inom exekveringsomfånget för en enda SELECT/INSERT/UPDATE/DELETE/MERGE/CREATE VIEW-sats. Det kan också referera till sig själv, vilket kallas rekursiv CTE.

Förbereder data

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

Skapa frågan

Först kommer vi att skriva en CTE som genererar alla datum inom datumintervallet.

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;

Nu kommer denna CTE att refaktoreras för att göra en underfråga med LEFT OUTER JOIN så att datumet som inte har värdet visas och innehåller värdet 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

Slutlig utdata

Slutsats

Hoppas, det kommer att vara till hjälp för dig. Glad TSQLing!

Den finns också i min personliga blogg!


  1. Hur man skapar ett Amazon Aurora-kluster

  2. SQLite Välj Distinct

  3. Utför denna tidsfråga i PostgreSQL

  4. Hur byter man namn på ett kolumnnamn i SQL?