根据条件将一列转换为两列

Convert one column to two column based on condition

我有一个 table 看起来像这样的:

TagName          DateTime        value
HA_06_ON    2020-07-07 08:52:14    1
HA_06_ON    2020-07-07 09:01:42    0
HA_06_ON    2020-07-07 09:02:17    1
HA_06_ON    2020-07-07 09:32:55    0
HA_06_ON    2020-07-07 09:33:21    1
HA_06_ON    2020-07-07 09:35:02    0
HA_06_ON    2020-07-07 09:35:27    1 
HA_06_ON    2020-07-07 09:35:44    0
HA_06_ON    2020-07-07 10:10:32    1
HA_06_ON    2020-07-07 10:10:40    0 

我想根据值(值 = 1 ==> 开始时间,值 = 0 ==> 结束时间)将此 table 转换为此值。

TagName        StartTime                EndTime
HA_06_ON   2020-07-07 08:52:14      2020-07-07 09:01:42
HA_06_ON   2020-07-07 09:02:17      2020-07-07 09:32:55
....

我曾尝试在 select 语句中使用 case when 但 return 像这样在每一列上都为 null

TagName           StartTime            EndTime
HA_06_ON      2020-07-07 08:57:07       NULL
HA_06_ON            NULL        2020-07-07 09:01:42
HA_06_ON      2020-07-07 09:02:17       NULL
HA_06_ON            NULL        2020-07-07 09:32:55
HA_06_ON      2020-07-07 09:33:21       NULL
HA_06_ON            NULL        2020-07-07 09:35:02

由于您此处没有分组列,我们必须做出一个假设:我们可以假设如果我们按日期排序,1 和 0 将交替出现,从而处理您的数据。否则没有解决方案,因为我们不知道如何将 1 与 0 相关联。

鉴于我们可以假定此顺序,我们可以使用 lag()lead() 来执行此操作。请注意,这假设您从 1 开始,并且每个 1 都有对应的 0。如果最后一个 1 没有对应的 0,则该行的 EndTime 将为空。

select  u.TagName, 
        u.StartTime, 
        u.EndTime 
from    (
        select  TagName, 
                StartTime = [DateTime] ,
                EndTime   = lead([DateTime], 1) over
                            (
                                partition by TagName
                                order by [Datetime] asc
                            ), 
                value 
        from t
        ) u
where   u.value = 1

有多种方法可以解决这个问题。如果我假设这些值是完全交错的,一种方法是聚合:

select tagname, min(datetime) as starttime, max(datetime) as endtime
from (select t.*,
             row_number() over (partition by tagname, value order by datetime) as seqnum
      from t
     ) t
group by tagname, seqnum;

只是因为我没有看到 sum() over 选项

例子

Select TagName
      ,StartTime = min(DateTime)
      ,EndTime   = max(DateTime)
 From ( 
        Select *
              ,Grp = sum(value) over (partition by TagName order by DateTime) 
         From @YourTable
      ) A
 Group By TagName,Grp

Returns

TagName     StartTime                   EndTime
HA_06_ON    2020-07-07 08:52:14.000     2020-07-07 09:01:42.000
HA_06_ON    2020-07-07 09:02:17.000     2020-07-07 09:32:55.000
HA_06_ON    2020-07-07 09:33:21.000     2020-07-07 09:35:02.000
HA_06_ON    2020-07-07 09:35:27.000     2020-07-07 09:35:44.000
HA_06_ON    2020-07-07 10:10:32.000     2020-07-07 10:10:40.000