Tuần trước, một đồng nghiệp của tôi đã yêu cầu tôi giúp anh ta viết một truy vấn để điền vào những ngày còn thiếu trong kết quả truy vấn. Tôi đã xem qua một số giải pháp, dường như không thuận tiện cho tôi. Vì vậy, tôi đã biên dịch của riêng mình bằng cách sử dụng CTE đệ quy hoặc Biểu thức bảng chung.
Tuyên bố sự cố
Giả sử chúng ta có một bảng chứa các bản ghi cuộc gọi đến của bộ phận chăm sóc khách hàng từ ngày 1 đến ngày 10 tháng 6 năm 2021. Trong một số ngày, không có bản ghi cuộc gọi nào. Nếu chúng tôi chạy câu lệnh GROUP BY trên cột datetime, một số ngày sẽ bị thiếu. Đầu ra mong muốn là, ngày bị thiếu sẽ là giá trị 0. Đầu ra mẫu sẽ ở bên dưới:
Truy vấn
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)
Đầu ra mẫu
Đầu ra mong muốn
Phương pháp tiếp cận giải pháp của tôi
Thay vì sử dụng truy vấn GROUP BY đơn giản, CTE và SUB QUERY được sử dụng. CTE đệ quy được sử dụng để tạo phạm vi ngày và LEFT OUTER JOIN được sử dụng để kết hợp giá trị với ngày. Hãy giải thích từng bước.
CTE / Biểu thức bảng chung
CTE hoặc Biểu thức bảng chung chỉ định một tập kết quả được đặt tên tạm thời được lấy từ một truy vấn đơn giản và được xác định trong phạm vi thực thi của một câu lệnh SELECT / INSERT / UPDATE / DELETE / MERGE / CREATE VIEW. Nó có thể tham chiếu đến chính nó cũng được gọi là CTE đệ quy.
Chuẩn bị dữ liệu
-- 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')
Xây dựng truy vấn
Đầu tiên, chúng tôi sẽ viết một CTE sẽ tạo ra tất cả các ngày trong phạm vi ngày.
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;
Bây giờ CTE này sẽ được cấu trúc lại để tạo một truy vấn phụ với LEFT OUTER JOIN để ngày không có giá trị xuất hiện và chứa giá trị 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
Đầu ra cuối cùng
Kết luận
Hy vọng, nó sẽ hữu ích cho bạn. Chúc bạn TSQLing vui vẻ!
Nó cũng có sẵn trong blog cá nhân của tôi!