3

タイムスタンプ付きのuser_idのログインデータのセットがあります。

ユーザーは複数回ログインできますが、最小レコードから始めて、互いに少なくとも1時間離れたレコードを返す必要があります。重複排除はユーザーレベルで行う必要があります(複数のユーザーが存在する可能性があります)

たとえば。

  • user1 2012-03-07 14:24:30.000
  • user1 2012-03-07 14:34:30.000
  • user1 2012-03-07 15:14:30.000
  • user1 2012-03-07 15:20:30.000
  • user1 2012-03-07 15:30:30.000
  • user1 2012-03-08 09:20:30.000
  • user1 2012-03-08 09:50:30.000
  • user1 2012-03-08 10:30:30.000
  • user2 2012-03-07 15:20:30.000

次のレコードだけを見たいです

  • user1 2012-03-07 14:24:30.000
  • user1 2012-03-07 15:30:30.000
  • user1 2012-03-08 09:20:30.000
  • user1 2012-03-08 10:30:30.000
  • user2 2012-03-07 15:20:30.000

================================================== ======================

これをクリーンな方法で行う方法はありますか?これは再帰的に行うことができますが、によってrow_numberパーティションを使用する方法があるのではないかと期待していました。

どんな助けでも大歓迎です!!

4

1 に答える 1

3

Sql Server 2005以降では、このCTEはLoginAt日時のテーブルを返し、すでに選択されているLoginAtsから1時間以内のテーブルを削除します。

;with SkipHour(UserID, LoginAT, rn) as (
  select UserID, min(LoginAt), cast (1 as bigint)
    from LogTable
   group by UserID
  union all
  select SkipHour.UserID, LogTable.LoginAt,
         row_number() over (partition by SkipHour.UserID 
                            order by Logtable.LoginAt) rn
  from SkipHour
     inner join LogTable
        on LogTable.UserID = SkipHour.UserID
     where datediff(minute, SkipHour.LoginAt, LogTable.LoginAt) >= 60
     -- Only first rows from previous generation qualify to have children
        and rn = 1
)
select *
from SkipHour
where rn = 1
order by UserID, LoginAT

重要な部分はrow_number()です。SQL Serverは集計関数も最上位述語も許可しないため、row_number()がloginAt日時を注文し、最初の1つだけを保持する唯一の方法(IMO)です。

SQLフィドルの遊び場はこの方法です。

更新

行番号は、世代ごとに個別に適用されます。WITH common_table_expression(Transact-SQL)からの抽出:

CTEの再帰部分の分析関数と集計関数は、CTEのセットではなく、現在の再帰レベルのセットに適用されます。ROW_NUMBERのような関数は、現在の再帰レベルによって渡されたデータのサブセットに対してのみ機能し、CTEの再帰部分に渡されたデータのセット全体に対しては機能しません。詳細については、J。再帰CTEでの分析関数の使用を参照してください。

于 2012-04-05T23:39:34.920 に答える