Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 如何计算一段时间内具有特定状态的用户数?_Sql_Sql Server - Fatal编程技术网

Sql 如何计算一段时间内具有特定状态的用户数?

Sql 如何计算一段时间内具有特定状态的用户数?,sql,sql-server,Sql,Sql Server,我需要从SQLServer2008R2中的UserHistory表创建一个报告。样本如下: 出于计费目的,我们需要计算在特定期间有多少不同的用户具有特定状态。周期可以低至1天,也可以高达2个月。因此,如果一个用户处于活动状态,不处于活动状态,然后在一段时间内再次处于活动状态,则该用户将被视为一个活动用户 曲线球现在进入比赛。如果我在指定的时间段内没有历史记录,则存储的进程需要在时间段开始之前查找第一个历史记录条目,以查看它是否与状态匹配。很明显,如果我在10月20日活跃,然后我的账户在11月1

我需要从SQLServer2008R2中的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个被取消的用户


有人有什么想法或更好的方法来做这件事吗?我真的需要一些输入。

我决定在整个范围内调用一次存储过程,它将返回所有符合我的条件的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中有更好的方法来实现这一点?