SQL:如果事件发生,将时间序列table转换为开始-结束时间table
SQL: transposing a time series table into a start-end time table if an event occur
我正在尝试使用 select 语句来创建视图,将带有日期时间的 table 转换为每行包含记录的 table,开始结束时间'record' 字段中按时间(按站点划分)的连续值不为 0。
这是初始 table 的示例。
以及转置后的样子。
有人能帮忙吗?
ROW_NUMBER() 最适合分区。接下来,您可以对分区表进行自连接,看看时间差是否大于五分钟。我认为最好的解决方案是根据时间戳差异的滚动总和进行分区,根据您的模式偏移 5 分钟。如果五分钟不是常规模式,那么可能有一种通用方法可以与零一起使用。
为方便视图创建而在下面编写为 CTE 的解决方案(尽管视图速度较慢)。
WITH partitioned as (
SELECT datetime, station, recording,
ROW_NUMBER() OVER(PARTITION BY station
ORDER BY datetime ASC) rn
FROM table --Not sure what the tablename is
WHERE recording != 0),
diffed as (
SELECT a.datetime, a.station,
DATEDIFF(mi,ISNULL(b.datetime,a.datetime),a.datetime)-5) Difference
--The ISNULL logic is for when a.datetime is the beginning of the block,
--we want a 0
FROM partitioned a
LEFT JOIN partitioned b on a.rn = b.rn + 1 and a.station=b.station
GROUP BY a.datetime,a.station),
cumulative as (
SELECT a.datetime, a.station, SUM(b.difference) offset_grouping
FROM diff a
LEFT JOIN diff b on a.datetime >= b.datetime and a.station = b.station ),
ordered as (SELECT datetime,station,
ROW_NUMBER() OVER(PARTITION BY station,offset_grouping ORDER BY datetime asc) starter,
ROW_NUMBER() OVER(PARTITION BY station,offset_grouping ORDER BY datetime desc) ender
FROM cumulative)
SELECT ROW_NUMBER() OVER(ORDER BY a.datetime) unique_id,a.station,a.datetime startdate, b.datetime enddate
FROM ordered a
JOIN ordered b on a.starter = b.ender and a.station=b.station and a.starter=1
这是我能想到的唯一解决方案,但同样,它的速度很慢,具体取决于您拥有的数据量。
您可以使用 conditional_change_event
分析函数来创建一个特殊的分组标识符,以便在一个简单的查询中将它们分开:
select row_number() over () unique_id,
station,
min(datetime) startdate,
max(datetime) enddate
from (
select t.*, CONDITIONAL_CHANGE_EVENT(decode(recording,0,0,1))
over (partition by station order by datetime) chg
from mytable t
) x
where recording > 0
group by station, chg
order by 1, 2
解码只是为了设置你的岛和间隙(其中间隙正在记录 <= 0 并且岛屿正在记录 > 0)。那么那上面的change事件就会生成一个新的标识符进行分组。另请注意,我正在对更改事件进行分组,即使它不是输出的一部分。
我正在尝试使用 select 语句来创建视图,将带有日期时间的 table 转换为每行包含记录的 table,开始结束时间'record' 字段中按时间(按站点划分)的连续值不为 0。
这是初始 table 的示例。
以及转置后的样子。
有人能帮忙吗?
ROW_NUMBER() 最适合分区。接下来,您可以对分区表进行自连接,看看时间差是否大于五分钟。我认为最好的解决方案是根据时间戳差异的滚动总和进行分区,根据您的模式偏移 5 分钟。如果五分钟不是常规模式,那么可能有一种通用方法可以与零一起使用。
为方便视图创建而在下面编写为 CTE 的解决方案(尽管视图速度较慢)。
WITH partitioned as (
SELECT datetime, station, recording,
ROW_NUMBER() OVER(PARTITION BY station
ORDER BY datetime ASC) rn
FROM table --Not sure what the tablename is
WHERE recording != 0),
diffed as (
SELECT a.datetime, a.station,
DATEDIFF(mi,ISNULL(b.datetime,a.datetime),a.datetime)-5) Difference
--The ISNULL logic is for when a.datetime is the beginning of the block,
--we want a 0
FROM partitioned a
LEFT JOIN partitioned b on a.rn = b.rn + 1 and a.station=b.station
GROUP BY a.datetime,a.station),
cumulative as (
SELECT a.datetime, a.station, SUM(b.difference) offset_grouping
FROM diff a
LEFT JOIN diff b on a.datetime >= b.datetime and a.station = b.station ),
ordered as (SELECT datetime,station,
ROW_NUMBER() OVER(PARTITION BY station,offset_grouping ORDER BY datetime asc) starter,
ROW_NUMBER() OVER(PARTITION BY station,offset_grouping ORDER BY datetime desc) ender
FROM cumulative)
SELECT ROW_NUMBER() OVER(ORDER BY a.datetime) unique_id,a.station,a.datetime startdate, b.datetime enddate
FROM ordered a
JOIN ordered b on a.starter = b.ender and a.station=b.station and a.starter=1
这是我能想到的唯一解决方案,但同样,它的速度很慢,具体取决于您拥有的数据量。
您可以使用 conditional_change_event
分析函数来创建一个特殊的分组标识符,以便在一个简单的查询中将它们分开:
select row_number() over () unique_id,
station,
min(datetime) startdate,
max(datetime) enddate
from (
select t.*, CONDITIONAL_CHANGE_EVENT(decode(recording,0,0,1))
over (partition by station order by datetime) chg
from mytable t
) x
where recording > 0
group by station, chg
order by 1, 2
解码只是为了设置你的岛和间隙(其中间隙正在记录 <= 0 并且岛屿正在记录 > 0)。那么那上面的change事件就会生成一个新的标识符进行分组。另请注意,我正在对更改事件进行分组,即使它不是输出的一部分。