我有一个需要从 SQL Server 2008 R2 中的 UserHistory 表创建的报告。示例如下:
出于计费目的,我们需要计算在特定时期内有多少不同用户具有特定状态。这段时间可以低至 1 天,也可以长达 2 个月。因此,如果一个用户在一段时间内处于活动状态、不活动状态然后再次处于活动状态,那么这将被视为一个活动用户。
曲线球现在可以上场了。如果我在指定时间段内没有历史记录,则存储过程需要在该时间段开始之前寻找第一个历史记录条目,以查看它是否与状态匹配。显然,如果我在 10 月 20 日活跃,然后我的帐户在 11 月 15 日被暂停,如果这段时间是 11 月,我仍然活跃。
起初,我用一个游标遍历每个用户表来执行此操作,并对每个用户及其用户历史进行查询,但是即使使用相关索引,200000 个用户也需要大约 40 秒。在 9 个状态期间,每天 40 秒加起来非常快。
我和我的同事想出了这个最接近的方法:
ALTER PROCEDURE [dbo].[cpUserHistory_CountByStatus] @StartDate DATETIME2,
@EndDate DATETIME2,
@Status VARCHAR(50)
AS
SET NOCOUNT ON
SELECT SUM(CASE WHEN CurrentMonth.UserId IS NOT NULL OR PreviousTime.UserId IS NOT NULL THEN 1 ELSE 0 END)
FROM [User]
LEFT JOIN
(SELECT UserId
FROM
UserHistory
INNER JOIN
(SELECT MAX(UserHistoryId) AS UserHistoryId
FROM UserHistory
WHERE EditedDate BETWEEN @StartDate AND @EndDate
GROUP BY UserId) LastStatus ON UserHistory.UserHistoryId = LastStatus.UserHistoryId
WHERE UserHistory.Status = @Status -- EDIT: Your status you're interested in
) CurrentMonth ON [User].UserId = CurrentMonth.UserId
LEFT JOIN
(SELECT UserId
FROM
UserHistory
INNER JOIN
(SELECT MAX(UserHistoryId) AS UserHistoryId
FROM UserHistory
WHERE EditedDate < @StartDate
GROUP BY UserId) LastStatus ON UserHistory.UserHistoryId = LastStatus.UserHistoryId
WHERE UserHistory.Status = @Status -- EDIT: Your status you're interested in
) PreviousTime ON [User].UserId = PreviousTime.UserId
但正如您在简化的报告示例中看到的那样,用户在当月 3 日被取消,然后在 5 日重新激活,但总数并未反映在此期间的某个时间点有 1 名用户被取消。
有没有人有任何想法或更好的方法来做到这一点?我真的可以使用一些输入。