如何在SQL中根据日期列和每个重复行划分的聚合列之间的差异来复制行?
我有一张关于油耗的记录表。表中的重要列是:消费日期从和消费日期到 我想每月计算每辆车的平均燃油消耗量,但有些行不在同一个月内。例如,其中一些有三个月的差异,每公升的总汽油量汇总在一行中 现在,我应该找到在CONSUME_DATE_FROM和CONSUM_DATE_TO之间相差超过一个月的记录,并在当前或第二个表中每个月的计数中复制它们,并在相关行之间除以每升总气体 我在该表中列出了以下数据:如何在SQL中根据日期列和每个重复行划分的聚合列之间的差异来复制行?,sql,oracle,Sql,Oracle,我有一张关于油耗的记录表。表中的重要列是:消费日期从和消费日期到 我想每月计算每辆车的平均燃油消耗量,但有些行不在同一个月内。例如,其中一些有三个月的差异,每公升的总汽油量汇总在一行中 现在,我应该找到在CONSUME_DATE_FROM和CONSUM_DATE_TO之间相差超过一个月的记录,并在当前或第二个表中每个月的计数中复制它们,并在相关行之间除以每升总气体 我在该表中列出了以下数据: ID VehicleId CONSUME_DATE_FROM CONSUM_DATE_TO
ID VehicleId CONSUME_DATE_FROM CONSUM_DATE_TO GAS_PER_LITER
1 100 2018-10-25 2018-12-01 600
2 101 2018-07-19 2018-07-24 100
3 102 2018-12-31 2019-01-01 400
4 103 2018-03-29 2018-05-29 200
5 104 2018-02-05 2018-02-09 50
预期输出表应如下所示
ID VehicleId CONSUME_DATE_FROM CONSUM_DATE_TO GAS_PER_LITER
1 100 2018-10-25 2018-12-01 200
1 100 2018-10-25 2018-12-01 200
1 100 2018-10-25 2018-12-01 200
2 101 2018-07-19 2018-07-24 100
3 102 2018-12-31 2019-01-01 200
3 102 2018-12-31 2019-01-01 200
4 103 2018-03-29 2018-05-29 66.66
4 103 2018-03-29 2018-05-29 66.66
4 103 2018-03-29 2018-05-29 66.66
5 104 2018-02-05 2018-02-09 50
或如下
ID VehicleId CONSUME_DATE_FROM CONSUM_DATE_TO GAS_PER_LITER DATE_RELOAD_GAS
1 100 2018-10-25 2018-12-01 200 2018-10-01
1 100 2018-10-25 2018-12-01 200 2018-11-01
1 100 2018-10-25 2018-12-01 200 2018-12-01
2 101 2018-07-19 2018-07-24 100 2018-07-01
3 102 2018-12-31 2019-01-01 200 2018-12-01
3 102 2018-12-31 2019-01-01 200 2019-01-01
4 103 2018-03-29 2018-05-29 66.66 2018-03-01
4 103 2018-03-29 2018-05-29 66.66 2018-04-01
4 103 2018-03-29 2018-05-29 66.66 2018-05-01
5 104 2018-02-05 2018-02-09 50 2018-02-01
有人能帮我解答这个问题吗
我使用的是oracle数据库您的业务规则将消费日期与消费日期之间的差异视为绝对月份。因此,您预计2018-10-25和2018-12-01之间的差异为三个月,而天数的差异实际上相当于约1.1个月。因此,我们不能使用简单的日期算法来获得所需的输出,我们需要对日期进行一些额外的处理 下面的查询实现了您所需的逻辑,方法是导出CONSUME_DATE_FROM的月份第一天和CONSUME_DATE_TO的月份最后一天,然后使用ceil将差值四舍五入到最接近的月份整数 这是在主查询中使用的子查询中计算的,该子查询使用旧的“按级别连接”技巧将记录乘以级别的次数:
with cte as (
select f.*
, ceil(months_between(last_day(CONSUM_DATE_TO)
, trunc(CONSUME_DATE_FROM,'mm'))) as diff
from fuel_consumption f
)
select cte.id
, cte.VehicleId
, cte.CONSUME_DATE_FROM
, cte.CONSUM_DATE_TO
, cte.GAS_PER_LITER/cte.diff as GAS_PER_LITER
, add_months(trunc(cte.CONSUME_DATE_FROM, 'mm'), level-1) as DATE_RELOAD_GAS
from cte
connect by level <= cte.diff
and prior cte.id = cte.id
and prior sys_guid() is not null
;
如果添加一个额外的列DATE\u RELOAD\u GAS来显示相似行的差异日期,会怎么样
从您发布的样本来看,似乎DATE_RELOAD_GAS是每个月的第一天,以CONSUME_DATE_From和CONSUM_DATE_TO为界。我已修改了我的解决方案以实现此规则。通过使用“按级别连接”结构,并考虑从+level-1、'yyyymm'开始使用日期,我可以解决以下问题:
我遇到了一个有趣的问题,如果我把子查询中的连接条件看作C.ID>=1,查询会在很长一段时间内挂起,所以通过联合所有的方法分成两个部分。 当c.ID>=2和c.ID=1时
为什么有些记录会被复制,而另一些记录会被复制成三份?我不明白你的逻辑。DATE\u RELOAD\u GAS从哪里来?它不在你的初始数据中???不,它不是我的初始数据。这只是计算后的一个新列。谢谢,它工作正常,但如果添加一个额外的列DATE_RELOAD_GAS,显示类似行的差异日期,该怎么办?谢谢让我检查一下谢谢,它工作正常,但是如果添加一个额外的列DATE\u RELOAD\u GAS来显示相似数据的差异日期呢rows@GhostMan不客气。在检测到myMonth后,它很简单。刚把我的月分成了两部分
select ID, VehicleId, myMonth, CONSUME_DATE_FROM, CONSUM_DATE_TO,
trunc(GAS_PER_LITER/max(rn) over (partition by ID order by ID),2) as GAS_PER_LITER,
'01.'||substr(myMonth,5,2)||'.'||substr(myMonth,1,4) as DATE_RELOAD_GAS
from
(
with consumption( ID, VehicleId, CONSUME_DATE_FROM, CONSUM_DATE_TO, GAS_PER_LITER ) as
(
select 1,100,date'2018-10-25',date'2018-12-01',600 from dual union all
select 2,101,date'2018-07-19',date'2018-07-24',100 from dual union all
select 3,102,date'2018-12-31',date'2019-01-01',400 from dual union all
select 4,103,date'2018-03-29',date'2018-05-29',200 from dual union all
select 5,104,date'2018-02-05',date'2018-02-09', 50 from dual
)
select ID, to_char(c.CONSUME_DATE_FROM + level - 1,'yyyymm') myMonth,
VehicleId, c.CONSUME_DATE_FROM, c.CONSUM_DATE_TO, GAS_PER_LITER,
row_number() over (partition by ID order by ID) as rn
from dual join consumption c
on c.ID >= 2
group by ID, to_char(c.CONSUME_DATE_FROM + level - 1,'yyyymm'), VehicleId,
c.CONSUME_DATE_FROM, c.CONSUM_DATE_TO, c.GAS_PER_LITER
connect by level <= c.CONSUM_DATE_TO - c.CONSUME_DATE_FROM + 1
union all
select ID, to_char(c.CONSUME_DATE_FROM + level - 1,'yyyymm') myMonth,
VehicleId, c.CONSUME_DATE_FROM, c.CONSUM_DATE_TO, GAS_PER_LITER,
row_number() over (partition by ID order by ID) as rn
from dual join consumption c
on c.ID = 1
group by ID, to_char(c.CONSUME_DATE_FROM + level - 1,'yyyymm'), VehicleId,
c.CONSUME_DATE_FROM, c.CONSUM_DATE_TO, c.GAS_PER_LITER
connect by level <= c.CONSUM_DATE_TO - c.CONSUME_DATE_FROM + 1
) q
group by ID, VehicleId, myMonth, CONSUME_DATE_FROM, CONSUM_DATE_TO, GAS_PER_LITER, rn
order by ID, myMonth;