Sql 如何计算一段时间内具有特定状态的用户数?
我需要从SQLServer2008R2中的UserHistory表创建一个报告。样本如下: 出于计费目的,我们需要计算在特定期间有多少不同的用户具有特定状态。周期可以低至1天,也可以高达2个月。因此,如果一个用户处于活动状态,不处于活动状态,然后在一段时间内再次处于活动状态,则该用户将被视为一个活动用户 曲线球现在进入比赛。如果我在指定的时间段内没有历史记录,则存储的进程需要在时间段开始之前查找第一个历史记录条目,以查看它是否与状态匹配。很明显,如果我在10月20日活跃,然后我的账户在11月15日被暂停,如果这段时间是11月,我仍然活跃 起初,我使用光标遍历每个用户表,并对每个用户及其用户历史进行查询,但即使使用相关索引,对于200000个用户,这也需要大约40秒。在9种状态中,每天40秒加起来非常快 我的同事和我想出了一个最接近的方法:Sql 如何计算一段时间内具有特定状态的用户数?,sql,sql-server,Sql,Sql Server,我需要从SQLServer2008R2中的UserHistory表创建一个报告。样本如下: 出于计费目的,我们需要计算在特定期间有多少不同的用户具有特定状态。周期可以低至1天,也可以高达2个月。因此,如果一个用户处于活动状态,不处于活动状态,然后在一段时间内再次处于活动状态,则该用户将被视为一个活动用户 曲线球现在进入比赛。如果我在指定的时间段内没有历史记录,则存储的进程需要在时间段开始之前查找第一个历史记录条目,以查看它是否与状态匹配。很明显,如果我在10月20日活跃,然后我的账户在11月1
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个被取消的用户
有人有什么想法或更好的方法来做这件事吗?我真的需要一些输入。我决定在整个范围内调用一次存储过程,它将返回所有符合我的条件的UserHistory条目,在代码中,我可以随意计数和过滤它 这并不理想,因为可能有相当多的数据从数据库传输到应用程序,一旦进入应用程序,它可以使用一点内存-但它可以工作,速度快,更重要的是准确
ALTER PROCEDURE [dbo].[cpUserHistory_SelectForBillingPeriod] @StartDate DATETIME2,
@EndDate DATETIME2
AS
BEGIN
DECLARE @Uh TABLE (
UserHistoryId INT,
UserId INT,
UserStatus VARCHAR(50),
EditedDate DATETIME2
)
INSERT INTO @Uh
SELECT UserHistoryId,
UserId,
[Status],
EditedDate
FROM UserHistory
WHERE EditedDate >= @StartDate
AND EditedDate <= @EndDate
INSERT INTO @Uh
SELECT UserHistory.UserHistoryId,
UserId,
[Status],
EditedDate
FROM UserHistory
INNER JOIN (
SELECT MAX(UserHistoryId) AS UserHistoryId
FROM UserHistory
WHERE EditedDate < @StartDate
GROUP BY UserId
) LastStatus ON UserHistory.UserHistoryId = LastStatus.UserHistoryId
SELECT *
FROM @Uh
order by EditedDate desc
它是从C调用的,所以也许在LINQ中有更好的方法来实现这一点?