![](/img/trans.png)
[英]SQL query to copy column from one table to another table based off index value
[英]Oracle - SQL query to bin the data from one table to another based on a column value?
什么 SQL 查询用于从Table1
生成Table2
(表如下所示)?
Table2
需要根据Table1.Status
字段将Table1
中的时间戳分为开始和结束时间。 结果Table2.Status
应该在每一行中在 0 和 1 之间切换。
Table2.StartTime
= Table1.Status
Table1.TimeStamp
1 变为 0 或反之亦然。
Table2.EndTime
= ( Table1.TimeStamp
of Table1.Status
next change 的第一个值) - 1 毫秒
Table1
中的第一条记录可以从任何Status
- 1 或 0 开始。
Table1
TimeStamp Status
11-NOV-11 12.45.45.445000000 AM 1
11-NOV-11 12.46.45.445000000 AM 1
11-NOV-11 12.47.45.445000000 AM 1
11-NOV-11 12.48.45.445000000 AM 0
11-NOV-11 12.49.45.445000000 AM 0
11-NOV-11 12.50.45.445000000 AM 1
11-NOV-11 12.51.45.445000000 AM 0
11-NOV-11 12.52.45.445000000 AM 0
11-NOV-11 12.53.45.445000000 AM 1
...
Table2
StartTime EndTime Status
11-NOV-11 12.45.45.445000000 AM 11-NOV-11 12.48.45.444000000 AM 1
11-NOV-11 12.48.45.445000000 AM 11-NOV-11 12.50.45.444000000 AM 0
11-NOV-11 12.50.45.445000000 AM 11-NOV-11 12.51.45.444000000 AM 1
11-NOV-11 12.51.45.445000000 AM 11-NOV-11 12.53.45.444000000 AM 0
...
任何帮助,将不胜感激。
select min(t2.TimeStamp) Start_time
, lead(min(t2.TimeStamp), 1)over(order by min(t2.TimeStamp)) - INTERVAL '0.001' SECOND End_time
, t2.status
from (
select t1.TimeStamp TimeStamp, STATUS, group_tag, first_value(group_tag ignore nulls)over(order by t1.TimeStamp ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) group_tag_gap_filling
from (
select t.TimeStamp, Status, case when lead(status, 1, 2)over(order by t.TimeStamp) != status then row_number()over(order by t.TimeStamp)end group_tag
from Table1 t
)t1
)t2
group by t2.group_tag_gap_filling, t2.status
;
首先,在内联视图“t1”中,我创建临时组然后其次,我填补所有临时组的空白然后我使用最小聚合 function 提取需要的内容,并引导分析 function,然后我从 end_time 中提取 0.001 秒
这是一个差距和孤岛问题,略有不同。 不同之处在于,您不想报告每个岛屿的最新时间戳记记录,而是想报告紧随该最新记录之后的记录。 因此,我们可以使用行号差法,也可以计算时间戳列的前导。
WITH cte AS (
SELECT t.*, ROW_NUMBER() OVER (ORDER BY ts) rn1,
ROW_NUMBER() OVER (PARTITION BY Status ORDER BY ts) rn2,
LEAD(ts) OVER (ORDER BY ts) AS ts_lead
FROM Table1 t
)
SELECT MIN(ts) AS StartTime, MAX(ts_lead) AS EndTime
FROM cte
GROUP BY Status, rn1 - rn2
HAVING MAX(ts_lead) IS NOT NULL
ORDER BY MIN(ts);
您可以使用analytical
函数和GROUP BY
实现它,如下所示:
SELECT MIN(TIMESTAMP) AS STARTTIME, MAX(TIMESTAMP) AS ENDTIME, STATUS
FROM
(SELECT T.TIMESTAMP, T.STATUS, SUM(CHANGE_POINT) OVER (ORDER BY TIMESTAMP) AS SM
FROM
(SELECT T.TIMESTAMP, T.STATUS,
CASE WHEN LAG(STATUS) OVER (ORDER BY TIMESTAMP) <> STATUS THEN 1 END AS CHANGE_POINT
FROM YOUR_TABLE T
) T
)
GROUP BY SM, STATUS
您还可以使用MATCH_RECOGNIZE
子句,如下所示:
SELECT * FROM YOUR_TABLE
MATCH_RECOGNIZE
(
ORDER BY TIMESTAMP
MEASURES
FIRST( TIMESTAMP ) AS STARTDATE,
LAST( TIMESTAMP ) AS ENDDATE,
FIRST( STATUS ) AS STATUS
ONE ROW PER MATCH
PATTERN( same_field+ )
DEFINE same_field AS FIRST(STATUS) = STATUS
);
有很多方法可以解决间隙和孤岛问题。 在这种情况下,最简单的方法是两个 window 函数和过滤:
select status, ts as start_time, lead(ts) over (order by ts) as end_time
from (select t1.*, lag(status) over (order by ts) as prev_status
from table1 t1
) t1
where prev_status is null or prev_status <> status
order by start_time;
逻辑很简单:
lead()
获取结束时间戳。这是一个 db<>fiddle。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.