对非唯一值进行分区

问题描述

我有一个表,该表列出了事件,事件中的操作以及每个操作的时间。事件ID不是唯一的,因为它是同一事件,只是发生在不同的时间。对于相同类型的事件,操作可能有所不同。同一事件永远不会连续运行两次。

我想按照给定的示例填充三个新列。这将使我能够对单独的事件进行分析,因为我将能够生成唯一的“事件” ID。

编辑: 我已经尝试过基于事件的PARTITION函数,但由于sql Server假定两个事件(A和B)并因此为所有“ A”事件提供了相同的开始日期,所以它没有用,即使实际上我需要将它们显示为单独的具有不同开始日期的事件。

Example

谢谢!

解决方法

这只是窗口功能:

select t.*,min(operationtime) over (partition by event) as event_start_time,max(operationtime) over (partition by event) as event_end_time,concat(event,'-',min(operationtime) over (partition by event)) as event_id
from t;

实际上,对于事件ID,您可能想要以下内容:

       concat(event,convert(varchar(255),min(operationtime) over (partition by event),101)) as event_id

或您想要的日期的任何格式。我建议使用YYYY-MM-DD作为日期格式。

,

此方法显式创建事件组,然后使用窗口查询与其他答案非常相似。我创建了一个简单的示例表来显示结果。

数据

drop table if exists #tTEST;
go
select * INTO #tTEST from (values 
('A','X','2020-01-08'),('A','Z','2020-02-08'),('B','2020-03-08'),'2020-04-08'),'2020-05-08'),'2020-06-08')) V([Event],[Operation],operation_time);

查询

;with
grp_cte as (
    select t.*,case when lag([Event],1,0) over (order by operation_time) != [Event] then 1 else 0 end grp_ind
    from #tTEST t),event_grp_cte as (
    select gc.*,sum(grp_ind) over (order by operation_time) EventGroup
    from grp_cte gc)
select 
    t.*,min(operation_time) over(partition by EventGroup) event_start_time,max(operation_time) over(partition by EventGroup) event_end_time,min(operation_time) over(partition by EventGroup)) event_id
from event_grp_cte t
order by operation_time;

结果

Event   Operation   operation_time  grp_ind EventGroup  rn1 rn2 event_start_time    event_end_time  event_id
A       X       2020-01-08  1   1   1   1   2020-01-08  2020-02-08  A-2020-01-08
A       Z       2020-02-08  0   1   2   2   2020-01-08  2020-02-08  A-2020-01-08
B       X       2020-03-08  1   2   3   1   2020-03-08  2020-04-08  B-2020-03-08
B       Z       2020-04-08  0   2   4   2   2020-03-08  2020-04-08  B-2020-03-08
A       X       2020-05-08  1   3   5   3   2020-05-08  2020-06-08  A-2020-05-08
A       Z       2020-06-08  0   3   6   4   2020-05-08  2020-06-08  A-2020-05-08
,

我理解这是一个“孤岛”问题,您想在其中建立连续的日常事件组。

一个选项使用行号之间的差异来标识组:

select 
    t.*,min(operation_time) over(partition by event,rn1 - rn2) event_start_time,max(operation_time) over(partition by event,rn1 - rn2) event_end_time,rn1 - rn2)) event_id
from (
    select 
        t.*,row_number() over(order by operation_time) rn1,row_number() over(partition by event order by operation_time) rn2
    from mytable t
) t
order by operation_time

如果每天总是只有一个事件(如示例数据所示),那么一个row_number()就足够了,以及日期运算:

select
    t.*,grp) event_start_time,grp) event_end_time,grp)) event_id
from (
    select 
        t.*,dateadd(
            day,- row_number() over(partition by event order by operation_time),operation_time
        ) grp
from mytable t
) t