sql >> Databáze >  >> RDS >> Sqlserver

Vyplňte chybějící data pro výstup dotazu SQL Server pomocí CTE

Minulý týden mě jeden z kolegů požádal, abych mu pomohl napsat dotaz na doplnění chybějících dat ve výstupu dotazu. Narazil jsem na několik řešení, ani jedno se mi nezdálo vhodné. Takže jsem sestavil svůj vlastní pomocí rekurzivního CTE nebo Common Table Expression.

Prohlášení o problému

Řekněme, že máme tabulku, která obsahuje záznamy o příchozích hovorech zákaznické péče od 1. do 10. června 2021. V některých dnech neexistuje žádný záznam hovorů. Pokud spustíme příkaz GROUP BY ve sloupci datetime, některé dny budou chybět. Požadovaný výstup je, chybějící data budou mít hodnotu 0. Ukázkový výstup bude níže:

Dotaz

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)

Ukázkový výstup

Požadovaný výstup

Můj přístup k řešení

Spíše než pomocí jednoduchého dotazu GROUP BY se používají CTE a SUB QUERY. Rekurzivní CTE se používá ke generování rozsahu dat a LEFT OUTER JOIN se používá ke spojení hodnoty s datem. Pojďme si to vysvětlit krok za krokem.

CTE/Common Table Expression

CTE nebo Common Table Expression určuje dočasnou pojmenovanou sadu výsledků, která je odvozena z jednoduchého dotazu a je definována v rozsahu provádění jediného příkazu SELECT/INSERT/UPDATE/DELETE/MERGE/CREATE VIEW. Může také odkazovat na sebe, což se nazývá rekurzivní CTE.

Příprava dat

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

Sestavení dotazu

Nejprve napíšeme CTE, která vygeneruje všechna data v daném časovém období.

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;

Nyní bude tento CTE refaktorován tak, aby byl vytvořen dílčí dotaz s LEFT OUTER JOIN, takže se objeví datum, které nemá hodnotu a obsahuje hodnotu 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

Konečný výstup

Závěr

Doufám, že to pro vás bude užitečné. Šťastné TSQLing!

Je také k dispozici na mém osobním blogu!


  1. MariaDB JSON_REMOVE() Vysvětleno

  2. Zdrojový formát SSIS Implicitní převod pro datum a čas

  3. Jak vložit řádky do tabulky SQL Server pomocí GUI pro úpravy řádků tabulky - SQL Server / Výukový program TSQL, část 101

  4. Je nutné DbCommand po použití zlikvidovat?