[英]Oracle - SQL query to bin the data from one table to another based on a column value?
What SQL query to use to generate Table2
from Table1
(tables shown below)?什么 SQL 查询用于从
Table1
生成Table2
(表如下所示)?
Table2
needs to bin the timestamps from Table1
into start and end times according to the Table1.Status
field. Table2
需要根据Table1.Status
字段将Table1
中的时间戳分为开始和结束时间。 As a result Table2.Status
should toggle between 0 and 1 in every row.结果
Table2.Status
应该在每一行中在 0 和 1 之间切换。
Table2.StartTime
= 1st value of Table1.TimeStamp
whenever Table1.Status
changes from 1 to 0 or viceversa. Table2.StartTime
= Table1.Status
Table1.TimeStamp
1 变为 0 或反之亦然。
Table2.EndTime
= (1st value of Table1.TimeStamp
of Table1.Status
next change) - 1millisecond Table2.EndTime
= ( Table1.TimeStamp
of Table1.Status
next change 的第一个值) - 1 毫秒
The first record in Table1
can start from any Status
- 1 or 0. 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
...
Any help would be appreciated.任何帮助,将不胜感激。
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
;
First, in inline view "t1", I create temporary groups Then Secondly, I fill in the gap for all temporary groups Then I extract what is need using min aggregation function, and lead analytic function, and I extract 0.001 second from end_time首先,在内联视图“t1”中,我创建临时组然后其次,我填补所有临时组的空白然后我使用最小聚合 function 提取需要的内容,并引导分析 function,然后我从 end_time 中提取 0.001 秒
This is a gaps and islands problem, with a slight twist.这是一个差距和孤岛问题,略有不同。 The twist being that you don't want to report the most recent timestamp record for each island, but rather you want to report the record immediately following after that most recent record.
不同之处在于,您不想报告每个岛屿的最新时间戳记记录,而是想报告紧随该最新记录之后的记录。 So, we can use the difference in row numbers method, and also compute the lead of the timestamp column.
因此,我们可以使用行号差法,也可以计算时间戳列的前导。
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);
You can achieve it using the analytical
functions and GROUP BY
as follows:您可以使用
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
You can also use the MATCH_RECOGNIZE
clause as follows:您还可以使用
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
);
There are many ways to solve gaps-and-islands problems.有很多方法可以解决间隙和孤岛问题。 In this case, the simplest method is two window functions and filtering:
在这种情况下,最简单的方法是两个 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;
The logic is simple:逻辑很简单:
lead()
to get the ending timestamp.lead()
获取结束时间戳。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.