Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Füllen Sie fehlende Daten für die SQL Server-Abfrageausgabe mit CTE aus

Letzte Woche hat mich einer meiner Kollegen gebeten, ihm beim Schreiben einer Abfrage zu helfen, um fehlende Daten in der Abfrageausgabe auszufüllen. Ich bin auf ein paar Lösungen gestoßen, keine schien mir bequem zu sein. Also habe ich meine eigene mit rekursivem CTE oder Common Table Expression kompiliert.

Problemstellung

Nehmen wir an, wir haben eine Tabelle, die eingehende Anrufaufzeichnungen einer Kundenbetreuung vom 1. bis 10. Juni 2021 enthält. An manchen Tagen gibt es keine Anrufaufzeichnung. Wenn wir die GROUP BY-Anweisung in der datetime-Spalte ausführen, fehlen einige Tage. Gewünschte Ausgabe ist, fehlende Daten haben den Wert 0. Beispielausgabe ist unten:

Abfrage

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)

Beispielausgabe

Gewünschte Ausgabe

Mein Lösungsansatz

Anstatt eine einfache GROUP BY-Abfrage zu verwenden, werden CTE und SUB QUERY verwendet. Der rekursive CTE wird verwendet, um den Datumsbereich zu generieren, und LEFT OUTER JOIN wird verwendet, um den Wert mit dem Datum zu kombinieren. Lass es uns Schritt für Schritt erklären.

CTE/allgemeiner Tabellenausdruck

CTE oder Common Table Expression gibt eine temporäre benannte Ergebnismenge an, die von einer einfachen Abfrage abgeleitet und innerhalb des Ausführungsbereichs einer einzelnen SELECT/INSERT/UPDATE/DELETE/MERGE/CREATE VIEW-Anweisung definiert wird. Es kann sich auch auf sich selbst beziehen, was als rekursiver CTE bezeichnet wird.

Daten vorbereiten

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

Erstellen Sie die Abfrage

Zuerst schreiben wir einen CTE, der alle Daten innerhalb des Datumsbereichs generiert.

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;

Jetzt wird dieser CTE umgestaltet, um eine Unterabfrage mit LEFT OUTER JOIN zu erstellen, sodass das Datum, das den Wert nicht hat, erscheint und den Wert 0 enthält.

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

Endgültige Ausgabe

Fazit

Hoffe, es wird für Sie hilfreich sein. Viel Spaß beim TSQLing!

Es ist auch in meinem persönlichen Blog verfügbar!