簡體   English   中英

PostgreSQL和多個匹配行

[英]PostgreSQL and matching row on multiple

我正在制定一種汽車統計解決方案,需要每行駛一公里就收費一次。

我有下表:

table: cars
columns: car_id, km_driven

table: pricing
columns: from, to, price

我的cars表中的內容可以是:

car_id, km_driven
2, 430
3, 112
4, 90

我的pricing表上的內容可以是:

from, to, price
0, 100, 2
101, 200, 1
201, null, 0.5

這意味着前100公里的價格為每公里2美元,接下來的100公里的價格為每公里1美元,而上述所有里程的價格為每公里0.5美元。

是否存在通過PostgreSQL計算我的cars成本的邏輯和簡單方法?

因此,如果car已經行駛。 201,那么價格將是100x2 + 100x1 + 0.5 ,而不是201x0.5

修改自@ 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> =開始被省略(它是可選的,但可能會提高性能)

多擺弄一下,在適當的位置可以省略大小寫

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

dbfiddle

我將查詢寫為:

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;

這是db <> fiddle

一定會使用一個過程來完成此操作,因為可以使用循環以非常簡單的方式來實現它。 但是,您應該能夠執行以下操作:

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。 鑒於此,以下內容應會給您希望。 (我還使用了“開始/結束”,因為“從/到”是保留字)。

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;

說明:

  1. 我們會加入旅程至少達到該范圍起點的任何范圍。
  2. 開放式范圍是在first case子句中處理的,非常簡單。
  3. 對於封閉范圍,我們需要一個內部case子句,因為我們只希望行程的一部分在該范圍內。
  4. 然后將其結果相加得出總旅程價格。

如果您不想(或無法)使范圍保持一致,則需要為起始范圍添加第三個外殼。

您可以使用join並通過用例計算成本

    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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM