根据条件将一列转换为两列
Posted
技术标签:
【中文标题】根据条件将一列转换为两列【英文标题】:Convert one column to two column based on condition 【发布时间】:2020-07-07 08:03:38 【问题描述】:我有一张像这样的表格:
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 ==> 结束时间)的表。
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,但像这样在每一列上返回 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
【问题讨论】:
这不是将一列转换为两列,这是一个间隙和孤岛问题 - 您正在尝试查找value
指定的孤岛的开始/结束值。 Gaps & islands
是该类别问题的实际名称。你可以谷歌它找到解决方案。在这种情况下,SUM (value) OVER(partition by TagName ORDER BY DateTime)
将为您提供一个 IslandID,您可以使用它来分组和提取 MIN(DateTime)
和 MAX(DateTime)
值。 SUM OVER
返回运行总数 value
。给定 value
的 ... 值,最终成为递增的 Island
ID
您不能对计算列进行分组,因此所有这些都应该包含在 CTE 中,例如 with islands AS (SELECT ... SUM() ... As IslandID FROM..) select TagName,MIN(DateTimeOffset),MAX(DateTime) from islands GROUP BY TagName,IslandID
顺序总是 1 -> 0 -> 1 -> 0 -> ... ?你能有 1 -> 0 -> 0 -> 1 吗?然后会发生什么?
Here is a good place to read about Gaps and Islands
@PanagiotisKanavos 非常感谢您的帮助!!!我已经搜索了差距和岛屿,并能够解决我的问题!!!
【参考方案1】:
由于您在这里没有分组列,我们必须做出一个假设:我们可以处理您的数据,假设如果我们按日期排序,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
【讨论】:
您需要通过tagname
进行分区。
没错,我不应该假设一个 TagName。【参考方案2】:
只是因为我没有看到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
退货
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
【讨论】:
【参考方案3】:有多种方法可以解决这个问题。如果我假设这些值是完全交错的,那么一种方法是聚合:
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;
【讨论】:
以上是关于根据条件将一列转换为两列的主要内容,如果未能解决你的问题,请参考以下文章