Oracle 按时间范围按 ID 聚合
Posted
技术标签:
【中文标题】Oracle 按时间范围按 ID 聚合【英文标题】:Oracle agregate by ID with time range 【发布时间】:2021-02-18 10:39:27 【问题描述】:我确定我在某处看到它,但我找不到它。 鉴于此表历史性:
ID1 | ID2 | Event_Date | Label |
---|---|---|---|
1 | 1 | 2020-01-01 | 1 |
1 | 1 | 2020-01-02 | 1 |
1 | 1 | 2020-01-04 | 1 |
1 | 1 | 2020-01-08 | 1 |
1 | 1 | 2020-01-20 | 1 |
1 | 1 | 2020-12-30 | 1 |
1 | 1 | 2020-01-01 | 0 |
1 | 1 | 2020-01-02 | 1 |
1 | 1 | 2020-01-04 | 0 |
1 | 1 | 2020-01-08 | 1 |
1 | 1 | 2020-01-20 | 0 |
1 | 1 | 2020-12-30 | 1 |
1 | 2 | 2020-01-01 | 1 |
1 | 2 | 2020-01-02 | 1 |
1 | 2 | 2020-01-04 | 1 |
2 | 1 | 2020-01-08 | 1 |
2 | 1 | 2020-01-20 | 1 |
2 | 1 | 2020-12-30 | 1 |
以及表格起点
ID1 | ID2 | Event_Date |
---|---|---|
1 | 1 | 2020-01-01 |
1 | 1 | 2020-01-02 |
1 | 1 | 2020-01-05 |
1 | 1 | 2020-01-08 |
1 | 1 | 2020-01-21 |
1 | 1 | 2021-01-01 |
1 | 1 | 2020-01-01 |
1 | 1 | 2020-01-03 |
1 | 1 | 2020-01-06 |
1 | 1 | 2020-01-11 |
1 | 1 | 2020-01-20 |
1 | 1 | 2020-12-31 |
1 | 2 | 2020-01-03 |
1 | 2 | 2020-01-05 |
1 | 2 | 2020-01-08 |
2 | 1 | 2020-01-08 |
2 | 1 | 2020-01-21 |
2 | 1 | 2021-01-01 |
对于起始点中的每一行,计算历史记录中具有相同 ID1 和 ID2 的行数,其中历史记录中的 Event_Date 介于 StartingPoint.Event_date - n 天之间(我将其设为 n 以便我可以更改不同的值)和StartingPoint.Event_date - 2 天。然后使用相同的规则计算 label = 1 的行的分数。
我知道我可以用 join 来做到这一点,但是如果历史和起点非常大,这看起来效率很低(对于起点中的每一行,它都会创建一个大的连接,最后它会汇总相同的集合行多次重复)。从抽象的角度来看,在我看来,最好先汇总每个 ID1、ID2、Event_date 的历史记录,并与起点连接并选择最佳的,但我对其他解决方案持开放态度。
【问题讨论】:
你必须加入他们,所以不太清楚你的意思。如果您有一些可行但您认为效率低下的东西(以及您为什么这么认为),则包含您对此数据的期望结果和当前查询可能会有所帮助。 【参考方案1】:您可以使用子查询尝试以下解决方案:
select * ,(select count(*) from historic h where h.id1=s.id1 and h.id2=s.id2 and h.event_date between dateadd(day,-30,s.event_date) and dateadd(day,-2,s.event_date) )from startingpoint s
【讨论】:
【参考方案2】:你必须有某种形式的加入;要么直接加入,要么使用标量子查询,这可能不会那么有效。
如果您只想查看具有历史数据的行,最简单的方法可能只是简单的连接:
select sp.id1, sp.id2, sp.event_date,
count(h.event_date) as any_label,
count(case when h.label = 1 then h.label end) as label_1,
count(case when h.label = 1 then h.label end) / count(h.event_date) as fraction_1
from startingpoint sp
join historic h on h.id1 = sp.id1
and h.id2 = sp.id2
and h.event_date >= sp.event_date - 10
and h.event_date < sp.event_date - 2
group by sp.id1, sp.id2, sp.event_date
order by sp.id1, sp.id2, sp.event_date;
其中 n 为 10;你的数据会给你:
ID1 ID2 EVENT_DATE ANY_LABEL LABEL_1 FRACTION_1
--- --- ---------- --------- ------- --------------------
1 1 2020-01-05 4 3 .75
1 1 2020-01-06 4 3 .75
1 1 2020-01-08 6 4 .6666666666666666667
1 1 2020-01-11 8 6 .75
1 2 2020-01-05 2 2 1
1 2 2020-01-08 3 3 1
或者如果你想看到零计数,你可以使用外连接;但是分数计算需要一些逻辑来避免被零除的错误:
select sp.id1, sp.id2, sp.event_date,
count(h.event_date) as any_label,
count(case when h.label = 1 then h.label end) as label_1,
case when count(h.event_date) > 0 then
count(case when h.label = 1 then h.label end) / count(h.event_date)
end as fraction_1
from startingpoint sp
left join historic h on h.id1 = sp.id1
and h.id2 = sp.id2
and h.event_date >= sp.event_date - 10
and h.event_date < sp.event_date - 2
group by sp.id1, sp.id2, sp.event_date
order by sp.id1, sp.id2, sp.event_date;
得到:
ID1 ID2 EVENT_DATE ANY_LABEL LABEL_1 FRACTION_1
--- --- ---------- --------- ------- --------------------
1 1 2020-01-01 0 0
1 1 2020-01-02 0 0
1 1 2020-01-03 0 0
1 1 2020-01-05 4 3 .75
1 1 2020-01-06 4 3 .75
1 1 2020-01-08 6 4 .6666666666666666667
1 1 2020-01-11 8 6 .75
1 1 2020-01-20 0 0
1 1 2020-01-21 0 0
1 1 2020-12-31 0 0
1 1 2021-01-01 0 0
1 2 2020-01-03 0 0
1 2 2020-01-05 2 2 1
1 2 2020-01-08 3 3 1
2 1 2020-01-08 0 0
2 1 2020-01-21 0 0
2 1 2021-01-01 0 0
db<>fiddle
【讨论】:
以上是关于Oracle 按时间范围按 ID 聚合的主要内容,如果未能解决你的问题,请参考以下文章