2016-03-24 7 views
0

はじめに:タイトルは申し訳ありませんが、実際はその質問については説明していません。お気軽に編集してください。ユーザのアクティビティを示しユーザーアクティビティに基づくユーザーセッション

データ:

actionid userid subjectid dtm 
1  1  1   2016-01-04 08:00:00.000 
2  1  1   2016-01-04 08:10:00.000 
3  1  1   2016-01-04 08:20:00.000 
4  1  1   2016-01-04 10:10:00.000 
5  1  1   2016-01-04 10:25:00.000 
11  1  2   2016-01-05 08:00:00.000 
12  1  2   2016-01-25 08:10:00.000 
13  1  2   2016-01-05 08:20:00.000 
14  1  2   2016-01-05 10:20:00.000 
15  1  2   2016-01-05 10:25:00.000 
16  2  1   2016-01-05 12:00:00.000 
17  2  1   2016-01-05 12:00:00.000 
18  2  3   2016-01-05 12:04:00.000 
19  2  3   2016-01-05 12:05:00.000 
20  2  1   2016-01-05 12:07:30.000 

A「セッション」は同じ座って行われたユーザアクティビティの集合として定義されます。セッションは、特定のサブジェクトで作業しているユーザーから始まり、(a)ユーザーが別のサブジェクトに切り替わるか、(b)60分が経過すると終了します。

目的は、セッションを識別し、セッションIDをすべてSQLで割り当てることです。標準SQLが推奨されますが、このデータはMicrosoft SQL Server上にあるため、CROSS APPLY、LEAD、LAGなどのT-SQL機能も使用できます。望ましい結果のようなものだろう

actionid userid subjectid dtm      sessionid 
1  1  1   2016-01-04 08:00:00.000 1 
2  1  1   2016-01-04 08:10:00.000 1 
3  1  1   2016-01-04 08:20:00.000 1 
4  1  1   2016-01-04 10:10:00.000 2 
5  1  1   2016-01-04 10:25:00.000 2 
11  1  2   2016-01-05 08:00:00.000 3 
12  1  2   2016-01-25 08:10:00.000 3 
13  1  2   2016-01-05 08:20:00.000 3 
14  1  2   2016-01-05 10:20:00.000 4 
15  1  2   2016-01-05 10:25:00.000 4 
16  2  1   2016-01-05 12:00:00.000 5 
17  2  1   2016-01-05 12:00:00.000 5 
18  2  3   2016-01-05 12:04:00.000 6 
19  2  3   2016-01-05 12:05:00.000 6 
20  2  1   2016-01-05 12:07:30.000 7 

私はこの例を使用して、明確にするため、再びロジックを説明します:ので

アクション#4は、セッション#1に所属するつもりはありませんそのセッションの最初のアクションから1時間以上です。セッション#2は、ユーザがサブジェクト2に切り替わると終了します。アクション#16と#17は同じ時間を持ち、それは問題ありません。アクション#20は、ユーザーが#18と#20の間でサブジェクトを切り替えたため、アクション#17の1時間以内であっても、新しいセッションになります。

+0

これはギャップや島のように思えますが、問題はいくつか考慮しなければなりません。 –

+0

サブクエリとランク付け関数を使用してこれを行うことができます。サブクエリを開始して、対象となる崖の上にあるかどうかに基づいて、すべてのレコードを0または1でシリアル化します。そのクエリを作成した後、上位から順に時間範囲をグループ化し、時間グループに基づいてランク付けし、件名の境界線を計算した0または1をグループ化できます。次に、3回目のパスまたはクエリーで目的の結果が得られます。 –

+0

アクションがdtmによって順序付けされている場合、アクション12は新しいセッションを取得する必要があります。そうしないと、このデータは正しくありません。 –

答えて

1

SQL Server 2012以降を使用している場合は、間違いなくLAG()を使用したいと考えています。ここでは、それを古い方法と比較して、ウィンドウ機能をLAG()と比較します。 LAG()

SELECT 
    *, 
    UserSubjectBoundryMarker=CASE WHEN LAG(subjectid, 1,0) OVER (ORDER BY userid,actionid) <> this.subjectID THEN 1 ELSE 0 END 
FROM 
    mytable this 

溶液を使用して

古い方法

SELECT 
    this.actionid, 
    this.userid, 
    this.subjectid, 
    this.dtm, 
    UserSubjectBoundryMarker=CASE WHEN prev.subjectid<>this.subjectid OR prev.subjectID IS NULL THEN 1 ELSE 0 END 
FROM 
(
    SELECT 
     *, 
     ID=ROW_NUMBER() OVER(PARTITION BY 1 order by userid,actionid) 
    FROM 
     mytable 
    )AS this 
    LEFT OUTER JOIN 
    (
     SELECT 
      *, 
      ID=ROW_NUMBER() OVER(PARTITION BY 1 order by userid,actionid) 
     FROM 
      mytable 
    ) 
    Prev ON (Prev.ID=this.ID-1) OR(Prev.ID IS NULL) 
ORDER BY 
    userid,dtm 

1. Mark dynamic subject group boundaries with a marker. 
2. Apply a dynamic group id to changes using max(change=1) + max(actionid) 
3. Mark dynamic hour group boundaries to the result of 2 with a marker. 
4. Apply a dynamic group id to the changes using max(change=1) + max(result of #2). 
5. Apply a dense rank to your outer group from #4 in a sequential order. 

SELECT 
    e.actionid, 
    e.userid, 
    e.subjectid, 
    e.dtm, 
    sessionid=DENSE_RANK() OVER(PARTITION BY 1 ORDER BY userid,subjectid,SubjectChangeGroupID,SubjectHourChangeBoundry,SubjectHourChangeGroupID ) 
FROM 
(
    SELECT 
     *, 
     SubjectHourChangeGroupID= 
      MAX(SubjectHourChangeBoundry) OVER (PARTITION BY userid,subjectid,SubjectChangeGroupID,SubjectHourChangeBoundry) 
      + 
      MAX(SubjectChangeGroupID) OVER (PARTITION BY userid,subjectid,SubjectChangeGroupID,SubjectHourChangeBoundry)  
    FROM 
    (

     SELECT 
      *, 
      SubjectHourChangeBoundry=CASE WHEN DATEDIFF(HOUR,MIN(C.dtm) OVER (PARTITION BY SubjectChangeGroupID),C.dtm) > 1 THEN 1 ELSE 0 END 
     FROM 
     (
      SELECT 
       *, 
       SubjectChangeGroupID= 
        MAX(UserSubjectBoundryMarker) OVER (PARTITION BY userid,subjectid) 
        + 
        MAX(actionid) OVER (PARTITION BY userid,subjectid) 
      FROM 
      (
       SELECT *,UserSubjectBoundryMarker=CASE WHEN LAG(a.subjectid, 1,0) OVER (ORDER BY a.userid,a.actionid) <> a.subjectID THEN 1 ELSE 0 END 
       FROM 
        mytable A 
      )AS B 
     )AS C 
    )AS D 
)AS E 
+0

私は両方のアプローチが好きです。私の挑戦は、境界を定義する2つの論理があるという事実にあります。 1つは過去のものであり、もう1つは主題の変更です。私が上記を理解すれば、それは主語の変化を捕捉するだけです。どのように私は両方をキャプチャできますか? – Merik

+0

私は、別のレベルを追加して、最終的なランク付けを適用して時間グループをマークし、一意に特定しました。これは助けになるはずです。 –

+0

ファナティック。それはトリックでした!明らかに、LAGとLEADは短くて実装が簡単です。 – Merik

関連する問題