2009-09-01 19 views
1

次のように私は、次の表の構造を持っている:(ブラックボックスを無視Excelで質問をフォーマットしてください。)トリッキー更新問題

alt text http://img525.imageshack.us/img525/5788/beforeznj.jpg

は、私は何をする必要があることにSessionGUIDデータを変換することですTSQLを使用して、以下: alt text http://img4.imageshack.us/img4/4553/afterjer.jpg

これは私のウェブサイトのためのユーザーセッションテーブルであり、それはすべてのページのロードに)(NEWIDを生成したことで、私たちはSessionGUID年代を台無しに。これで、作成された最初のSessionGUIDを使用して、ユーザーが最後のページロードから30分後にページ読み込みをトリガーしない場合、セッションが中断されたと仮定して、タイミングによってセッションをグループ化する必要があります。

さらに簡単な例を説明すると、User(00000000-0000-0000-0000-000000000000)は09/01/2009に自分のサイトを2回訪問しました。 1つは13:37に、もう1つは14:46に。ユーザー(A107EF1E-00A2-4515-A120-984086BC8368)。実際の表には、更新が必要な数百万の行が含まれていることに注意してください。 :(

UPDATE ランディングページ/各セッションのURLを開始するには、常に「ホームページ」ではありません、それはウェブサイト上の任意のページである可能性があります。プロットが厚く..

アップデート2テストデータ

CREATE TABLE Sessions (IPAddress VARCHAR(15), UserGUID UNIQUEIDENTIFIER, DATE DATETIME, URL VARCHAR(200), SessionGUID UNIQUEIDENTIFIER) 
INSERT INTO Sessions (
    IPAddress, 
    UserGUID, 
    DATE, 
    URL, 
    SessionGUID 
) 
VALUES ('192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009 13:37:34', 'homepage', '2B3A80B1-A247-4BB5-81BB-B54DED0C9C6A') 
VALUES ('192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009 13:37:36', 'page1', '7FB10E12-5EB9-428C-BE3E-57818DEF8512') 
VALUES ('192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009 13:37:41', 'page2', 'D12C3539-1239-447E-8BD8-DBA6B7087ADE') 
VALUES ('192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009 14:56:00', 'homepage', '4FE36C46-640B-464F-8118-AFFE477347A1') 
VALUES ('192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009 14:56:10', 'page2', 'FF9BF55B-3630-4D05-AB57-1B6ECAB96657') 
VALUES ('192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009 14:56:18', 'page4', '863D3424-9788-481A-8440-09313ED4F8FE') 
VALUES ('192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009 14:56:19', 'page3', '105D7FE5-C731-4EB6-B287-720127AAF0A3') 
VALUES ('192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009 15:00:35', 'page5', '296479D0-3848-4189-94E2-41906BAE580D') 
VALUES ('192.168.0.1', '00000000-0000-0000-0000-000000000000', '09/01/2009 15:00:36', 'page7', 'E3FFEBC6-C11E-4DF4-81FA-B42F1BF7AFD3') 
VALUES ('212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '12/01/2009 18:30:22', 'homepage', '1F918AB3-34E1-4343-8462-FA56423B921D') 
VALUES ('212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '12/01/2009 18:34:26', 'page1', '801C3DC8-F0F3-4B9C-BD53-BCCBE784CFAE') 
VALUES ('212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '12/01/2009 18:38:17', 'page2', 'A9A5C2BD-31B9-4A9B-A8BC-88C460F17282') 
VALUES ('212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009 11:42:27', 'page3', 'B29CE754-C7A3-40E8-8CB0-216A3E852762') 
VALUES ('212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009 11:42:32', 'page4', 'E291C4B9-A422-4A76-A550-F65C208DD886') 
VALUES ('212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009 11:44:51', 'page6', '63D4A636-8336-44E7-8C97-9CD65D21359E') 
VALUES ('212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009 11:44:55', 'page2', '7BB814CD-C9B3-4CAF-A45C-4405DC0B07D2') 
VALUES ('212.1.1.0', 'A107EF1E-00A2-4515-A120-984086BC8368', '15/01/2009 11:48:35', 'page4', 'B6DCEC1E-C262-425D-8E46-8F4B47F2921A') 

感謝。

不幸DBA新人。

+0

。そのため、1分ごとに1分ごとに配信されたWebページがあるユーザーは、45分間何もしないと、最初の1時間は1セッションになりますか?あなたのウェブサイトを知らないので、それが意味をなさないかどうかわかりません。 –

+0

あなたはそうです。それが私の言うことです。今更新しています。 – super9

+0

申し訳ありませんが、今日はこの時間がありません。インスピレーションのためにhttp://stackoverflow.com/questions/1287148/t-sql-query-to-flag-repeat-records/1292182#1292182をご覧ください。セッションの開始時刻と終了時刻で定義された可能なセッションを作成し、最初のセッションから開始し、再帰的なCTEで可能なセッションテーブルを歩きます。 –

答えて

1

EDIT私がテストしていないので、私は、構文エラーの数を持っていました。 (自分自身に注意し、テストコードなしで回答を提出しないでください)そして、一旦構文を修正してテストデータに対して実行したら、私の答えは間違っていました。 30分以内に行が存在するかどうかのサブクエリ・テストは、完全に偽でした。

修正されたバージョン:

; with EliminateTies (UserGuid, SessionGuid, "Date") as 
    (select UserGuid 
     , cast(min(cast(SessionGuid as varbinary)) as uniqueidentifier) 
     , "Date" 
    from Sessions 
    group by UserGuid, "Date") 
, SessionBoundaries (UserGuid, SessionGuid, StartDateTime, SessionNumber) as 
    (select UserGuid, SessionGuid, "Date" 
     , row_number() over 
      (partition by UserGuid 
      order by "Date") as SessionNumber 
    from (select UserGuid, SessionGuid, "Date" from EliminateTies 
     union all 
     -- Add a set of records at the end of time, to bound the last 
     -- of each users sessions 
     select distinct UserGuid 
      , null as SessionGuid 
      , cast('9999-12-31' as datetime) as "Date" 
     from Sessions) ET_Out 
    where not exists (select * 
     from EliminateTies ET_In 
     where ET_Out.UserGuid = ET_In.UserGuid 
     and ET_Out.SessionGuid <> ET_In.SessionGuid 
     and (dateadd(minute, -30, ET_Out."Date") < ET_In."Date" 
      and ET_In."Date" <= ET_Out."Date"))) 
Update MT 
    set SessionGuid = LowBound.SessionGuid 
from SessionBoundaries LowBound 
inner join SessionBoundaries HighBound 
    on LowBound.UserGuid = HighBound.UserGuid 
    and LowBound.SessionNumber = HighBound.SessionNumber - 1 
inner join Sessions S 
    on S.UserGuid = LowBound.UserGuid 
    and LowBound.StartDateTime <= S."Date" 
    and S."Date" < HighBound.StartDateTime 

EDIT 2の追加説明:

  1. ; with EliminateTies ...がEliminateTiesと呼ばれる関係を定義します。これは、(UserGuid, "Date")に対してトリプル(UserGuid, SessionGuid, "Date")に重複が含まれる可能性を処理するためです。 SQL Serverのdatetimeは1/300秒の解像度を持つため、重複はありませんが、不可能ではありません。
    1. エリミネータティには、(UserGuid, "Date")のペアgroup by UserGuid, "Date"ごとに1つの行が含まれます。
    2. SessionGuidは、そのペアに利用可能なSessionGuidのセットから、agregateファンクションmin()によって任意に選択されます。コメントで指摘されているように、MIN(GUID)は許可されていないので、VARBINARYへのキャスト、MIN()が見つかり、キャストバックUNIQUEIDENTIFIERに戻ります。
    3. 注:
      1. SQL Serverは、通常の文の末尾にセミコロンを必要としませんが、それは自分自身を再教育しようとしているwith ...代わりに先立つ文の場合にはないので、私はセミコロンで始まりますすべてのステートメントをセミコロンで終了するには、私はすべてwith ...というセミコロンで開始するように訓練しました。セミコロンは実際には以前のステートメントを終了します。
      2. dateはSQL Server 2008のデータ型であり、そこでは予約語であるため、 "Date"識別子を引用しています。 OPは2005年であり、厳密には慎重ではない。
  2. , SessionBoundaries別の関係
  3. が定義されています。この関係には、最後の30分以内にセッションにエントリがない場合、特定のUserGuidセッションの開始ルールに基づいて新しいセッションが開始されるすべてのポイントがあります。
    1. インラインビューfrom (select ... union all ...) ET_Out各UserGuidの「終了時刻」に日付を含む余分な行を追加します。これは、高い境界と低い境界の間で行をグループ化し、すべてのユーザーの最後のセッションの上限を必要とするためです。
    2. where not existsは、セッション境界の先頭にない行を除外します。
    3. row_number() ...は、すべてのUserGuidSessionNumberの1.N + 1(Nはセッションの数)を持つように、日付順の行に番号を付けます。後で、近隣の境界を見つけるためにSessionNumbersを使用します。 (SessionBoundaryNumberとよく呼ぶことができました)
  4. 最後に更新しました。関係を結びつけることを可能にするために、from節を追加します。更新はfrom句から更新したいテーブルのテーブルエイリアスを指定します。 (これは、T-SQLとではないビューで一緒に複数のリレーションを使用するためのANSI標準的な方法であることに注意してください。)
    1. まず自己UserGuid上とSessionNumberに基づいて、近隣の境界であることによって平等でSessionBoundaryに参加。ユーザーAが2セッションの場合、3 SessionNumber 1、2 & 3となります。この結合により(1,2)&(2,3)の(Low、High)ペアが生成されます。今度はUserGuidごとに、すべてのセッションの下限と上限の境界があります。最後のセッションの上限は「時間の終わり」です。
    2. 次に、更新するテーブルに参加するSessions結合条件はUserGuidが等しく、Sessionsの行の日付が[LowBound、HighBound]で定義された範囲内にあることです。境界がセッションを開始する場所であることを忘れないでください。したがって、テストはLowBound < =セッション。 "Date" < HighBoundです。それは、ユーザが(たとえば15分または30分)しばらくの間、非アクティブとなっているセッションの切れ目と言うことでより多くの意味を成していないだろう「1つのセッションはせいぜい30分が続くと仮定すると、」
+0

OKギミ二 – super9

+0

1は、MIN(SessionGUID)を処分した - MIN/MAXは、それが今の「無効なオブジェクト名 『ElminateTies』」 – super9

+0

が追加SessionGUID言って のGROUP BYにGUID 2.追加SessionGUIDに取り組んでいません〜によってグループは助けにはならない。 EliminateTiesのポイントは、同じUserGuidの同じdatetimeを持つ2つの行(可能性はあるものの、おそらく可能な場合)を処理することです。そして、はい、数多くのタイプミスがありました。テストデータをありがとう。 –

1

あなたのコメントの追加データに基づいて、のテーブルに十分な情報がないと結論して、このアップデートを作成してください。いくつかの分析を行い、グループ化してチャールズ・ブレタナの方法などを使って1回限りの修正に使用できる許容時間を見つけることができますが、その分析は自分で行うことができます。その番号または任意の番号を数えて長期的に仕事を続けます。

+0

ここで問題になるのは難しいことです。ランディングページは常に「ホームページ」ではありません – super9

+0

その場合、実際にはホームページを示す信頼できる方法が必要です。それ以外の場合は、タイムスタンプでグルーピングすることに頼らざるを得ません。あなたは30分のような素敵なものを選ぶことができますが、最終的には長い間走るセッションがいくつかあります。それに合わせてタイムアウトを延ばすと、最終的に2人のユーザーセッションが一緒になり、グループ内で重複してしまうことになります。 –

+0

うーん...それでも十分ではないかもしれません。セッション中にユーザーがホームページを2回以上ヒットしないと言う人は誰ですか?しかし、私は考えがあります。私にしばらく時間をつけて、私が何かを考え出すことができるかどうかを見てみましょう。 –

0

この記事は正しく表示されますか?

UPDATE T Set SessionGuid = 
    (Select Min(UserGuid) FROM [mytable] 
    Where IPAddress=T.IPAddress 
     And Date = (Select Min(Date) From MyTable 
        Where IPAddress = T.IPAddress 
         And DateDiff(minute, Date, T.Date) 
           Between 0 and 30)) 
FROM [mytable] T 
+0

あなたのサブクエリで2つ以上の値が返されていて好きではありません。 – super9

+0

@Nai、これは同じIPAddressと正確に同じdatetimeを持つ複数の行がある場合にのみ発生します。しかし、それは彼らが言うように、それで私はそれを処理するためにSQLを編集しました。再試行する? –

+0

より大きなデータセットでセッションを正しく結合していません。お疲れ様でした。 – super9