Oracle SQL - 仅按附近的相同记录分组
Oracle SQL - group only by nearby same records
我需要对值列相同的记录的延迟时间求和(以秒为单位)。问题是我只需要将它们按相同的块分组而不是全部放在一起。例如,对于下面的数据,我需要对值 3 的 3 条记录求和,并分别对更下方的 2 条记录求和,而不是对值 4 的记录求和,因为它们不在一起。有办法吗?
ID Value Timestamp Delay(s)
166549627 4 19-OCT-21 11:00:19 11.4
166549450 8 19-OCT-21 11:00:27 7.5
166549446 3 19-OCT-21 11:00:34 7.1
166549625 3 19-OCT-21 11:00:45 10.9
166549631 3 19-OCT-21 11:00:58 13.3
166550549 3 19-OCT-21 11:01:03 4.5
166549618 7 19-OCT-21 11:01:14 8.8
166549627 4 19-OCT-21 11:01:23 11.4
166550549 3 19-OCT-21 11:01:45 4.5
166550549 3 19-OCT-21 11:01:59 4.5
如果您想使用 PL/SQL,您可以遍历按时间戳排序的所有记录。
只要记住最后一个值,如果与当前值相同则求和。如果没有,就将总和保存到其他地方并继续。
您也可以将其编写为流水线函数,以使用查询访问数据。
declare
l_sum number := 0;
l_last_val number;
begin
for rec in (select * from your_table order by timestamp) loop
if l_last_val = rec.value then
l_sum := l_sum + rec.delay;
continue;
elsif l_last_val is not null then
dbms_output.put_line('value: ' || l_last_val || ' sum: ' || l_sum); -- save last_val and sum
end if;
l_last_val := rec.val;
l_sum := rec.delay;
end loop;
dbms_output.put_line('value: ' || l_last_val || ' sum: ' || l_sum); -- save last_val and sum
end;
您甚至不需要为此目的使用 plsql。只有 SQL 就足够了。
下面的解决方案使用 递归通用 table 表达式 (CTE) 技术根据值列和时间戳列创建子组。
with ranked_rows (ID, VALUE, TIMESTAMP, DELAY, RNB) as (
select ID, VALUE, TIMESTAMP, DELAY, row_number()over(order by TIMESTAMP) rnb
from YourTable
)
, cte (ID, VALUE, TIMESTAMP, DELAY, RNB, grp) as (
select ID, VALUE, TIMESTAMP, DELAY, RNB, 1 grp
from ranked_rows
where rnb = 1
union all
select t.ID, t.VALUE, t.TIMESTAMP, t.DELAY, t.RNB, case when c.VALUE = t.VALUE then c.grp else c.grp + 1 end
from ranked_rows t
join cte c on c.rnb + 1 = t.rnb
)
select VALUE, sum(DELAY) sum_consecutive_DELAY, min(TIMESTAMP) min_TIMESTAMP, max(TIMESTAMP) max_TIMESTAMP, count(*)nb_rows
from cte
group by VALUE, GRP
order by min_TIMESTAMP
;
我需要对值列相同的记录的延迟时间求和(以秒为单位)。问题是我只需要将它们按相同的块分组而不是全部放在一起。例如,对于下面的数据,我需要对值 3 的 3 条记录求和,并分别对更下方的 2 条记录求和,而不是对值 4 的记录求和,因为它们不在一起。有办法吗?
ID Value Timestamp Delay(s) 166549627 4 19-OCT-21 11:00:19 11.4 166549450 8 19-OCT-21 11:00:27 7.5 166549446 3 19-OCT-21 11:00:34 7.1 166549625 3 19-OCT-21 11:00:45 10.9 166549631 3 19-OCT-21 11:00:58 13.3 166550549 3 19-OCT-21 11:01:03 4.5 166549618 7 19-OCT-21 11:01:14 8.8 166549627 4 19-OCT-21 11:01:23 11.4 166550549 3 19-OCT-21 11:01:45 4.5 166550549 3 19-OCT-21 11:01:59 4.5
如果您想使用 PL/SQL,您可以遍历按时间戳排序的所有记录。
只要记住最后一个值,如果与当前值相同则求和。如果没有,就将总和保存到其他地方并继续。
您也可以将其编写为流水线函数,以使用查询访问数据。
declare l_sum number := 0; l_last_val number; begin for rec in (select * from your_table order by timestamp) loop if l_last_val = rec.value then l_sum := l_sum + rec.delay; continue; elsif l_last_val is not null then dbms_output.put_line('value: ' || l_last_val || ' sum: ' || l_sum); -- save last_val and sum end if; l_last_val := rec.val; l_sum := rec.delay; end loop; dbms_output.put_line('value: ' || l_last_val || ' sum: ' || l_sum); -- save last_val and sum end;
您甚至不需要为此目的使用 plsql。只有 SQL 就足够了。 下面的解决方案使用 递归通用 table 表达式 (CTE) 技术根据值列和时间戳列创建子组。
with ranked_rows (ID, VALUE, TIMESTAMP, DELAY, RNB) as (
select ID, VALUE, TIMESTAMP, DELAY, row_number()over(order by TIMESTAMP) rnb
from YourTable
)
, cte (ID, VALUE, TIMESTAMP, DELAY, RNB, grp) as (
select ID, VALUE, TIMESTAMP, DELAY, RNB, 1 grp
from ranked_rows
where rnb = 1
union all
select t.ID, t.VALUE, t.TIMESTAMP, t.DELAY, t.RNB, case when c.VALUE = t.VALUE then c.grp else c.grp + 1 end
from ranked_rows t
join cte c on c.rnb + 1 = t.rnb
)
select VALUE, sum(DELAY) sum_consecutive_DELAY, min(TIMESTAMP) min_TIMESTAMP, max(TIMESTAMP) max_TIMESTAMP, count(*)nb_rows
from cte
group by VALUE, GRP
order by min_TIMESTAMP
;