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

Inserisci le date mancanti per l'output di query di SQL Server utilizzando CTE

La scorsa settimana uno dei miei colleghi mi ha chiesto di aiutarlo a scrivere una query per riempire le date mancanti nell'output della query. Mi sono imbattuto in un paio di soluzioni, nessuna delle quali mi è sembrata conveniente. Quindi, ho compilato il mio usando CTE ricorsivo o Common Table Expression.

Dichiarazione del problema

Supponiamo di avere una tabella che contiene i record delle chiamate in entrata di un servizio clienti dal 1° al 10 giugno 2021. In alcuni giorni, non c'è alcun record delle chiamate. Se eseguiamo l'istruzione GROUP BY sulla colonna datetime, mancheranno alcuni giorni. L'output desiderato è che le date mancanti avranno un valore 0. L'output di esempio sarà il seguente:

Interroga

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)

Esempio di output

Uscita desiderata

Il mio approccio alla soluzione

Anziché utilizzare una semplice query GROUP BY, vengono utilizzati CTE e SUB QUERY. CTE ricorsivo viene utilizzato per generare l'intervallo di date e LEFT OUTER JOIN viene utilizzato per combinare il valore con la data. Spieghiamo passo dopo passo.

Espressione CTE/tabella comune

CTE o Common Table Expression specifica un set di risultati denominato temporaneo derivato da una semplice query e definito nell'ambito di esecuzione di una singola istruzione SELECT/INSERT/UPDATE/DELETE/MERGE/CREATE VIEW. Può riferirsi anche a se stesso che è chiamato CTE ricorsivo.

Preparazione dei dati

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

Crea la query

Per prima cosa, scriveremo un CTE che genererà tutte le date all'interno dell'intervallo di date.

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;

Ora questo CTE verrà rifattorizzato per creare una sottoquery con LEFT OUTER JOIN in modo che la data che non ha il valore appaia e contenga 0 valore.

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

Risultato finale

Conclusione

Spero, ti sarà utile. Buon TSQL!

È disponibile anche nel mio blog personale!