sql >> Database >  >> RDS >> Sqlserver

Vul ontbrekende datums in voor uitvoer van SQL Server-query's met behulp van CTE

Vorige week vroeg een van mijn collega's me om hem te helpen een query te schrijven om ontbrekende datums in de query-uitvoer in te vullen. Ik kwam een ​​paar oplossingen tegen, geen van beide leek me handig. Dus heb ik mijn eigen gecompileerd met recursieve CTE of Common Table Expression.

Probleemstelling

Laten we zeggen dat we een tabel hebben met inkomende oproeprecords van een klantenservice van 1 tot 10 juni 2021. Op sommige dagen is er geen oproeprecord. Als we de GROUP BY-instructie in de datetime-kolom uitvoeren, zullen enkele dagen ontbreken. Gewenste uitvoer is, ontbrekende datums hebben een waarde van 0. Voorbeelduitvoer vindt u hieronder:

Zoekopdracht

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)

Voorbeelduitvoer

Gewenste output

Mijn benadering van oplossing

In plaats van een eenvoudige GROUP BY-query te gebruiken, worden CTE en SUB QUERY gebruikt. Recursieve CTE wordt gebruikt om het datumbereik te genereren en LEFT OUTER JOIN wordt gebruikt om de waarde met de datum te combineren. Laten we het stap voor stap uitleggen.

CTE/Common Table Expression

CTE of Common Table Expression specificeert een tijdelijke benoemde resultatenset die is afgeleid van een eenvoudige query en is gedefinieerd binnen het uitvoeringsbereik van een enkele SELECT/INSERT/UPDATE/DELETE/MERGE/CREATE VIEW-instructie. Het kan ook naar zichzelf verwijzen, wat recursieve CTE wordt genoemd.

Gegevens voorbereiden

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

Bouw de zoekopdracht

Eerst zullen we een CTE schrijven die alle datums binnen het datumbereik zal genereren.

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 wordt deze CTE aangepast om een ​​subquery te maken met LEFT OUTER JOIN, zodat de datum die de waarde niet heeft verschijnt en 0 waarde bevat.

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

Definitieve output

Conclusie

Hoop, het zal nuttig voor je zijn. Veel plezier met TSQLing!

Het is ook beschikbaar in mijn persoonlijke blog!


  1. Wat betekenen geclusterde en niet-geclusterde index eigenlijk?

  2. Top 10 best practices in MySQL

  3. Een gids voor MySQL-indexen

  4. Selecteer Bulk Collect in Oracle-voorbeeld