Sql server SQL Server-如何根据值的最新更改对系列中的行进行分组?

Sql server SQL Server-如何根据值的最新更改对系列中的行进行分组?,sql-server,Sql Server,我有一个记录会话和事件的数据库。事件表包括时间戳和用户名。一个用户可以是匿名的,也可以在任何给定会话中登录尽可能多的不同用户 我正在尝试根据事件时间戳和用户名更改创建登录会话标识符。我可以根据时间戳对事件进行排序,并且可以看到用户名何时更改,但我无法确定如何将每个事件行与其相应的“登录会话”关联,该会话标识用户名更改时的最新事件 我已经创建了这个示例来模拟我需要做的事情a.ord是一个连续序列中的序号,a.val是一个值b.pval是序列中的前一个值 with a as ( select

我有一个记录会话和事件的数据库。事件表包括时间戳和用户名。一个用户可以是匿名的,也可以在任何给定会话中登录尽可能多的不同用户

我正在尝试根据事件时间戳和用户名更改创建登录会话标识符。我可以根据时间戳对事件进行排序,并且可以看到用户名何时更改,但我无法确定如何将每个事件行与其相应的“登录会话”关联,该会话标识用户名更改时的最新事件

我已经创建了这个示例来模拟我需要做的事情
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
我需要以某种方式返回左连接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

谢谢你的帮助

我是在试图为这个问题写一个可读的标题时发现的

答案如下:

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

使用伊齐克·本·甘(Izzik Ben Gan)对岛屿和缺口的解决方案(由米凯尔·埃里克森(Mikael Eriksson)向我介绍)变得非常简单
grouped
检索
a
中的所有记录,该记录由列
grp
扩充,其中包含一个数字,该数字在两个序列进行时保持不变。此数字和
val
的组合是唯一的。在主查询中,选择由这两个值分组的最小值(ord)


.

我的解决方案很有效,但在我的较大数据集上速度非常慢。这很有效,而且速度相当快。非常感谢您为我指出了正确的方向。+1用于使用min(x)over(partition by y)而不是分组子查询。
; 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