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!