Sqlserver
 sql >> база данни >  >> RDS >> Sqlserver

Попълнете липсващите дати за изход на заявка на SQL Server с помощта на CTE

Миналата седмица един от моите колеги ме помоли да му помогна да напише заявка, за да попълни липсващите дати в изхода на заявката. Попаднах на няколко решения, нито едното не ми се стори удобно. И така, компилирах моя собствена, използвайки рекурсивно CTE или Common Table Expression.

Постановка на проблема

Да кажем, че имаме таблица, която съдържа записи на входящи обаждания за обслужване на клиенти от 1 до 10 юни 2021 г. В някои дни няма запис на обажданията. Ако изпълним оператора GROUP BY в колона datetime, някои дни ще липсват. Желаният изход е, липсващите дати ще бъдат стойност 0. Примерен изход ще бъде по-долу:

Запитване

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)

Примерен изход

Желан изход

Моят подход към решение

Вместо да се използва проста заявка GROUP BY, се използват CTE и SUB QUERY. Рекурсивният CTE се използва за генериране на диапазона от време, а LEFT OUTER JOIN се използва за комбиниране на стойността с датата. Нека обясним стъпка по стъпка.

CTE/Общ израз на таблица

CTE или Common Table Expression определя временен набор от именуван резултат, който е извлечен от проста заявка и дефиниран в рамките на обхвата на изпълнение на един израз SELECT/INSERT/UPDATE/DELETE/MERGE/CREATE VIEW. Може да се отнася и за себе си, което се нарича рекурсивен CTE.

Подготовка на данни

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

Създайте заявката

Първо, ще напишем CTE, който ще генерира всички дати в рамките на диапазона от време.

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;

Сега този CTE ще бъде рефакториран, за да се направи подзаявка с LEFT OUTER JOIN, така че датата, която няма стойността, да се появи и да съдържа стойност 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

Краен изход

Заключение

Надявам се, че ще ви бъде полезно. Честит TSQLing!

Предлага се и в моя личен блог!


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Какво е съхранена процедура?

  2. Проверете дали низът съдържа знаци с ударение в SQL?

  3. Трикове за непрекъснато подобряване на мониторинга на базата данни

  4. Сравнение на SQL низове, по-голямо и по-малко от операторите

  5. Извикване на API от съхранената процедура на SQL Server