1. ホーム
  2. sql

[解決済み] 最小連続アクセス日数を決定するSQL?

2022-08-03 21:46:52

質問

次のユーザー履歴テーブルには あるユーザがWebサイトにアクセスした日ごとの記録 (24時間のUTC期間において) のレコードが含まれています。何千ものレコードがありますが、一人のユーザーにつき一日一レコードのみです。もしユーザーがその日にウェブサイトにアクセスしなかった場合、レコードは生成されません。

ID UserId CreationDate
------ ------ ------------
750997 12 2009-07-07 18:42:20.723
750998 15 2009-07-07 18:42:20.927
751000 19 2009-07-07 18:42:22.283

私が求めているのは、このテーブルに対する SQL クエリです。 良いパフォーマンスで どのユーザー ID が (n) 連続で 1 日も欠かさずウェブサイトにアクセスしたかを教えてくれるものです。

言い換えれば 何人のユーザーがこのテーブルで連続した(前日または後日)日付の(n)レコードを持っているか。 ? もし、いずれかの日がシーケンスから欠落している場合、シーケンスは壊れており、1から再び開始する必要があります。私たちは、ここでギャップなしで連続した日数を達成したユーザーを探しています。

このクエリと 特定の Stack Overflow バッジ はもちろん単なる偶然です... :)

どのように解決するのですか?

答えは明らかです。

SELECT DISTINCT UserId
FROM UserHistory uh1
WHERE (
       SELECT COUNT(*) 
       FROM UserHistory uh2 
       WHERE uh2.CreationDate 
       BETWEEN uh1.CreationDate AND DATEADD(d, @days, uh1.CreationDate)
      ) = @days OR UserId = 52551

EDITです。

さて、ここからは私の真面目な回答です。

DECLARE @days int
DECLARE @seconds bigint
SET @days = 30
SET @seconds = (@days * 24 * 60 * 60) - 1
SELECT DISTINCT UserId
FROM (
    SELECT uh1.UserId, Count(uh1.Id) as Conseq
    FROM UserHistory uh1
    INNER JOIN UserHistory uh2 ON uh2.CreationDate 
        BETWEEN uh1.CreationDate AND 
            DATEADD(s, @seconds, DATEADD(dd, DATEDIFF(dd, 0, uh1.CreationDate), 0))
        AND uh1.UserId = uh2.UserId
    GROUP BY uh1.Id, uh1.UserId
    ) as Tbl
WHERE Conseq >= @days

EDITです。

[Jeff Atwood] これは素晴らしい高速なソリューションであり、受け入れられるに値しますが Rob Farley の解決策も素晴らしいものです。 であり、間違いなくさらに高速です(!)。こちらもぜひご覧ください。