0

セッションとイベントをログに記録するデータベースがあります。イベントテーブルには、タイムスタンプとユーザー名が含まれています。ユーザーは匿名であるか、特定のセッション中に同じ数の異なるユーザーにログインする可能性があります。

イベントのタイムスタンプとユーザー名の変更に基づいて、ログインセッション識別子を作成しようとしています。タイムスタンプに基づいてイベントを並べ替えることができ、ユーザー名がいつ変更されるかを確認できますが、すべてのイベント行を、ユーザー名が変更されたときの最新のイベントを識別するそれぞれの「ログインセッション」に関連付ける方法がわかりません。

私は、私がする必要があることをモデル化するこの例を作成しました。a.ordは途切れのないシリーズの序数でありa.val、値です。b.pvalシリーズの先行値です。

with a as (
    select 1 AS ord, 'abc' as val union
    select 2, 'xyz' union
    select 3, 'abc' union
    select 4, 'abc' union
    select 5, 'xyz' union
    select 6, 'xyz' union
            select 7, 'xyz'
),
b as (
    select
        a1.ord as ord,
        a1.val as val,
        a2.val as pval
    from a a1
    left join a a2 on a1.ord - 1 = a2.ord 
    where a1.val != isnull(a2.val, '')
)
select
    *
from b

上記のコードは、値がnullから "abc"に変更されたときの最初の行を含め、値が変更された行を返します。これが返されるものです:

ORD VAL PVAL
1   abc NULL
2   xyz abc
3   abc xyz
5   xyz abc

a left join b「ORD」がa.ord、「VAL」がa.val、「CHG」がb.ordのように、どういうわけか戻る必要があります。

ORD VAL CHG
1   abc 1
2   xyz 2
3   abc 3
4   abc 3
5   xyz 5
6   xyz 5
7   xyz 5

ご協力いただきありがとうございます!

4

2 に答える 2

2

島とギャップに対する Itzik Ben-Gan のソリューション (この SO の質問に答えて Mikael Eriksson によって提示された) を使用すると、非常に簡単になります。2 つのシーケンスが進行しても変わらない数値を保持する、拡張された列groupedからすべてのレコードを取得します。この数字の組み合わせはユニークです。メイン クエリでは、この 2 つの値でグループ化された min(ord) を選択します。agrpval

これが例のSql Fiddleです

; with a as (
    select 1 AS ord, 'abc' as val union all
    select 2, 'xyz' union all
    select 3, 'abc' union all
    select 4, 'abc' union all
    select 5, 'xyz' union all
    select 6, 'xyz' union all
    select 7, 'xyz'
),
grouped as (
    select *,
           row_number() over (order by ord)
         - row_number() over (order by val, ord) grp
      from a
)
select ord, 
       val, 
       min(ord) over(partition by grp, val) chg
  from grouped
 order by ord

そしていくつかの読み物

于 2012-09-06T20:04:52.353 に答える
0

質問の読みやすいタイトルを書こうとしているときに、私はそれを理解しました。

答えは次のとおりです。

with a as (
    select 1 AS ord, 'abc' as val union
    select 2, 'xyz' union
    select 3, 'abc' union
    select 4, 'abc' union
    select 5, 'xyz' union
    select 6, 'xyz' union
    select 7, 'xyz'
),
b as (
    select
        a1.ord ord,
        a1.val val,
        a2.val sval
    from a a1
    left join a a2 on a1.ord - 1 = a2.ord 
    where a1.val != isnull(a2.val, '')
)
select
    *
from a
outer apply (
    select
        MAX(ord) as chg
    from b
    where a.val = b.val
    and a.ord >= b.ord
) x
于 2012-09-06T18:26:42.173 に答える