CTE_Users
cung cấp cho chúng tôi danh sách tất cả người dùng với Ngày bắt đầu và Ngày kết thúc cho mỗi người dùng.
Nó được kết hợp với Calendar
bảng để tạo hàng cho mỗi ngày cho mỗi người dùng.
Cuối cùng, nó được kết hợp với bảng chính Test
để trả về Total
cho mỗi ngày. ISNULL
đảm bảo rằng những ngày không có dữ liệu trả về 0.
WITH
CTE_Users
AS
(
SELECT
Userid
,MIN(startdate) AS StartDate
,MAX(enddate) AS EndDate
FROM TEST
GROUP BY Userid
)
SELECT
ROW_NUMBER() OVER (ORDER BY CTE_Users.Userid, Calendar.dt) AS ID
,CTE_Users.Userid
,T.Id1
,Calendar.dt
,ISNULL(T.Total, 0) AS Total
FROM
CTE_Users
INNER JOIN Calendar ON
Calendar.dt >= CTE_Users.StartDate
AND Calendar.dt <= CTE_Users.EndDate
LEFT JOIN TEST AS T ON
T.Userid = CTE_Users.Userid
AND T.date1 = Calendar.dt
ORDER BY CTE_Users.Userid, Calendar.dt;
Kết quả
| ID | Userid | Id1 | dt | Total |
|----|--------|--------|------------|-------|
| 1 | abc | 1 | 2015-01-13 | 200 |
| 2 | abc | 2 | 2015-01-14 | 200 |
| 3 | abc | 3 | 2015-01-15 | 200 |
| 4 | abc | (null) | 2015-01-16 | 0 |
| 5 | abc | (null) | 2015-01-17 | 0 |
| 6 | abc | (null) | 2015-01-18 | 0 |
| 7 | abc | 4 | 2015-01-19 | 200 |
| 8 | abc | 5 | 2015-01-20 | 200 |
| 9 | abc | (null) | 2015-01-21 | 0 |
| 10 | abc | (null) | 2015-01-22 | 0 |
| 11 | abc | 6 | 2015-01-23 | 200 |
| 12 | abc | 7 | 2015-01-24 | 200 |
| 13 | def | (null) | 2015-02-10 | 0 |
| 14 | def | (null) | 2015-02-11 | 0 |
| 15 | def | 8 | 2015-02-12 | 200 |
| 16 | def | 9 | 2015-02-13 | 200 |
| 17 | def | (null) | 2015-02-14 | 0 |
| 18 | def | 10 | 2015-02-15 | 200 |
| 19 | def | 11 | 2015-02-16 | 200 |
| 20 | def | 12 | 2015-02-17 | 200 |
| 21 | def | 13 | 2015-02-18 | 200 |
| 22 | def | (null) | 2015-02-19 | 0 |
| 23 | def | (null) | 2015-02-20 | 0 |
ID
là một số hàng được tạo nhanh chóng. Id1
là ID gốc từ Test
bàn.
Tôi sẽ tạo Calendar
bảng như thế này:
CREATE TABLE [Calendar](
[dt] [date] NOT NULL
CONSTRAINT [PK_Calendar] PRIMARY KEY CLUSTERED
(
[dt] ASC
));
-- 10K dates from 2000-01-01 till 2027-05-18
INSERT INTO Calendar (dt)
SELECT TOP (10000)
DATEADD(day, ROW_NUMBER() OVER (ORDER BY s1.[object_id])-1, '2000-01-01') AS dt
FROM sys.all_objects AS s1 CROSS JOIN sys.all_objects AS s2
OPTION (MAXDOP 1);