Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PostgreSQL和多行上的匹配行_Sql_Postgresql - Fatal编程技术网

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。在我看来,结果是正确的。