SQL Server 2008 R2 の UserHistory テーブルからレポートを作成する必要があります。以下にサンプルを示します。
請求の目的で、特定の期間にわたって特定のステータスを持っていた個別のユーザーの数を計算する必要があります。期間は最短で 1 日、最長で 2 か月程度です。したがって、1 人のユーザーがアクティブで、アクティブではなく、その後再びアクティブになった場合、それは 1 人のアクティブ ユーザーとしてカウントされます。
カーブボールが登場します。指定された期間内に履歴がなかった場合、ストアド プロシージャは期間の開始前に最初の履歴エントリを探して、それがステータスと一致するかどうかを確認する必要があります。明らかに、10 月 20 日にアクティブだったアカウントが 11 月 15 日に停止された場合、その期間が 11 月だった場合、私はまだアクティブでした。
最初は、各 User テーブルを通過するカーソルでこれを行い、ユーザーごとにクエリを実行し、ユーザー履歴を実行しましたが、関連するインデックスを使用しても、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 人いたことは合計に反映されていません。
これを行うためのアイデアやより良い方法はありますか? 私は本当にいくつかの入力を使用できます。