sql >> Database teknologi >  >> RDS >> Sqlserver

Udfyld manglende datoer for SQL Server-forespørgselsoutput ved hjælp af CTE

I sidste uge bad en af ​​mine kolleger mig om at hjælpe ham med at skrive en forespørgsel for at udfylde manglende datoer i forespørgselsoutput. Jeg stødte på et par løsninger, ingen af ​​dem virkede praktiske for mig. Så jeg kompilerede min egen ved hjælp af rekursiv CTE eller Common Table Expression.

Problemerklæring

Lad os sige, at vi har en tabel, der indeholder registreringer af indgående opkald fra en kundeservice fra 1. til 10. juni 2021. Nogle dage er der ingen opkaldspost. Hvis vi kører GROUP BY-sætningen på datetime-kolonnen, vil nogle dage mangle. Ønsket output er, manglende datoer vil være 0 værdi. Eksempeloutput vil være nedenfor:

Forespørgsel

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)

Eksempeloutput

Ønsket output

Min tilgang til løsning

I stedet for at bruge simpel GROUP BY-forespørgsel, bruges CTE og SUB QUERY. Rekursiv CTE bruges til at generere datointervallet, og LEFT OUTER JOIN bruges til at kombinere værdien med datoen. Lad os forklare trin-for-trin.

CTE/fælles tabeludtryk

CTE eller Common Table Expression angiver et midlertidigt navngivet resultatsæt, som er afledt af en simpel forespørgsel og defineret inden for eksekveringsomfanget af en enkelt SELECT/INSERT/UPDATE/DELETE/MERGE/CREATE VIEW-sætning. Det kan også referere til sig selv, hvilket kaldes rekursiv CTE.

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

Byg forespørgslen

Først vil vi skrive en CTE, som genererer alle datoer inden for datointervallet.

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 vil denne CTE blive refaktoreret for at lave en underforespørgsel med LEFT OUTER JOIN, så den dato, der ikke har værdien, vises og indeholder 0-værdien.

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

Endelig output

Konklusion

Håber, det vil være nyttigt for dig. Glad TSQLing!

Den er også tilgængelig på min personlige blog!


  1. Giv alle på et specifikt skema i db'en til en grupperolle i PostgreSQL

  2. Hvad er fordelen ved at bruge SET XACT_ABORT ON i en lagret procedure?

  3. PSQLEundtagelse:FEJL:Relationen TABLE_NAME eksisterer ikke

  4. PostgreSQL Column eksisterer ikke, men det gør den faktisk