PostgreSQL和多行上的匹配行
我正在做一个汽车统计解决方案,我需要按每公里行驶收费 我有下表:PostgreSQL和多行上的匹配行,sql,postgresql,Sql,Postgresql,我正在做一个汽车统计解决方案,我需要按每公里行驶收费 我有下表: table: cars columns: car_id, km_driven table: pricing columns: from, to, price “我的汽车”表中的内容可以是: car_id, km_driven 2, 430 3, 112 4, 90 from, to, price 0, 100, 2 101, 200, 1 201, null, 0.5 我的定价表中的内容可以是: car_id, km_dr
table: cars
columns: car_id, km_driven
table: pricing
columns: from, to, price
“我的汽车”表中的内容可以是:
car_id, km_driven
2, 430
3, 112
4, 90
from, to, price
0, 100, 2
101, 200, 1
201, null, 0.5
我的定价表中的内容可以是:
car_id, km_driven
2, 430
3, 112
4, 90
from, to, price
0, 100, 2
101, 200, 1
201, null, 0.5
也就是说,前100公里每公里的成本为2美元,下一个100公里每公里的成本为1美元,以上每公里的成本为0.5美元
是否有一种逻辑和简单的方法通过PostgreSQL计算我的汽车成本
因此,如果一辆汽车驾驶ex.201,那么价格将是100x2+100x1+0.5,而不仅仅是201x0.5。您可以使用join,并在以下情况下使用case计算成本:
select c.car_id, case when p.price=.5
then 100*2+100*1+(c.km_driven-200)*0.5
when p.price=1 then 100*2+(c.km_driven-100)*1
else c.km_driven*p.price as cost
from cars c join pricing p
on c.km_driven>=p.from and c.km_driven<=p.to
我肯定会使用过程来实现这一点,因为它可以使用循环以非常简单的方式实现。但是,您应该能够执行类似的操作:
select car_id, sum(segment_price)
from (
select
car_id,
km_driven,
f,
t,
price,
driven_in_segment,
segment_price
from (
select
car_id,
km_driven,
f,
t,
price,
(coalesce(least(t, km_driven), km_driven) - f) driven_in_segment,
price * (coalesce(least(t, km_driven), km_driven) - f) segment_price
from
-- NOTE: cartesian product here
cars,
pricing
where f < km_driven
)
) data
group by car_id
order by car_id
不过,我觉得这很难理解
更新:
这个查询比必要的要复杂一些,我尝试了一些最终不需要的窗口函数。此处的简化版本应等效:
select car_id, sum(segment_price)
from (
select
car_id,
km_driven,
f,
t,
price,
(coalesce(least(t, km_driven), km_driven) - f) driven_in_segment,
price * (coalesce(least(t, km_driven), km_driven) - f) segment_price
from
-- NOTE: cartesian product here
cars,
pricing
where f < km_driven
) data
group by car_id
order by car_id
明智地使用大小写/和组合。但是,首先需要使您的范围保持一致。我将选择将第一个范围更改为1100。考虑到这一点,下面应该给出你想要的。我还使用了start/finish作为from/to作为保留字
select
car_id, km_driven,
sum (case
when finish is null and km_driven >= start
then (km_driven-start+1) * price
when km_driven >= start
then (case
when (km_driven - start + 1) > finish
then (finish - start + 1)
else (km_driven - start + 1)
end) * price
else 0
end) as dist_price
from cars, pricing
where km_driven >= start
group by 1, 2;
说明:
我们加入到任何一个射程中,只要射程至少达到射程的起点。
开放范围在第一个case子句中处理,非常简单。
对于闭合范围,我们需要一个内部case子句,因为我们只需要该范围内的部分行程。
然后将计算结果相加,得出总旅程价格。
如果您不想或无法使范围保持一致,则需要为起始范围添加第三个外壳。根据@sean johnston的答案修改:
select
car_id, km_driven,
sum(case
when km_driven>=start then (least(finish,km_driven)-start+1)*price
else 0
end) as dist_price
from cars,pricing
group by car_id,km_driven
保持原来的射程
其中km_driven>=start省略了其可选功能,但可能会提高性能
若再做一点修改,那个么在适当的地方就可以省略这个案例
select
car_id, km_driven,
sum((least(finish,km_driven)-start+1)*price) as dist_price
from cars,pricing
where km_driven >= start
group by car_id,km_driven
我将把查询写为:
select c.car_id, c.km_driven,
sum(( least(p.to_km, c.km_driven) - p.from_km + 1) * p.price) as dist_price
from cars c join
pricing p
on c.km_driven >= p.from_km
group by c.car_id, c.km_driven;
这是一个。这是什么?你是说行驶公里的总价吗?是的,对不起。我错了。不,没有简单的方法可以做到这一点。对于每个车辆条目,您必须循环浏览定价表,并逐步应用公里的定价。最好的工具是编程语言。我想这可以通过PL/pgSQL实现。否则,你可以用任何其他语言编写应用程序。在SQL中,您将对此使用递归查询。1避免使用from和to作为标识符,它是保留字。2对于计算,使用半开放区间更为方便,例如,{100200}我认为这不会考虑到前100公里的总成本为2美元,下100公里的成本为1美元。因此,如果一辆汽车已经开过ex.201,那么价格将是100x2+100x1+0.5,而不仅仅是201x0.5。@AlfredBalle将这个例子放在了问题上,请确保工作完美。你认为带循环的过程会更好,还是更可读?我认为可读性更强,性能可能稍差。start+1不应该只是start吗?似乎提供了更准确的结果?p.from_km+1不应该简单地用p.from_km来获得更准确的结果吗?否则会在错误的范围内增加1公里。@AlfredBalle。在我看来,结果是正确的。