2016-04-14 6 views
1

私は都市間の接続を持つ大きなデータベースを持っています。各接続には、開始と終了の町、開始日、およびその接続の価格があります。postgresqlで順列を計算するには?

私は、任意の接続と、戻り接続が1〜20日の日付の任意の組み合わせを計算したいと思います。次に、それぞれの日付の組み合わせの最適な価格を選択します。

例:

表:

city_start,  city_end, date_start,  price 
Hamburg   Berlin  01.01.2016  100.00 
Berlin   Hamburg  10.01.2016  112.00 
Berlin   Hamburg  10.01.2016  70.00 
Berlin   Hamburg  12.01.2016  50.00 
Berlin   Hamburg  30.02.2016  20.00 
Paris   Madrid  ... 
Madrid   Paris 
London   Paris 

望ましい結果:

Hamburg-Berlin-Hamburg, 01.01.2016, 10.01.2016, 170.00 (100+70) 
Hamburg-Berlin-Hamburg, 01.01.2016, 12.01.2016, 150.00 (100+50) 
... 
(not Berlin-Hamburg on 30.02.2016 because it's >20 days from departure drive) 
(not London-Paris, as there is no return Paris-London) 

私がで可能な組み合わせを得ることができます。

SELECT DISTINCT city_start, city_end, city_end, city_start from table 

しかし、私は今、どのように計算することができます彼らの順守ns?すべてのペアを取得する

答えて

2

クエリがjoinを使用しています。

select tto.city_start, tto.city_end, tto.date_start, tfrom.date_end, 
     (tto.price + tfrom.price) as price 
from t tto join 
    t tfrom 
    on tto.city_end = tfrom.city_start and 
     tto.city_start = tfrom.city_end and 
     tfrom.date_start >= tto.date_start + interval '1 day' and 
     tfrom.date_end <= tto.date_start + interval '20 day'; 

ウィンドウ関数を使用し、最も安い価格を取得するには:ここで

select tt.* 
from (select tto.city_start, tto.city_end, tto.date_start, tfrom.date_end, 
      (tto.price + tfrom.price) as price, 
      row_number() over (partition by tto.city_start, tto.city_end order by (tto.price + tfrom.price) asc) as seqnum 
     from t tto join 
      t tfrom 
      on tto.city_end = tfrom.city_start and 
       tto.city_start = tfrom.city_end and 
       tfrom.date_start >= tto.date_start + interval '1 day' and 
       tfrom.date_end <= tto.date_start + interval '20 day' 
    ) tt 
where seqnum = 1; 
+0

偉大な、それは一般的に動作するようです。 row_numberパーティション部分に代わる方法はありますか? (なぜならwindowAggr関数のパフォーマンスはかなり悪いからです)。 – membersound

1

は、ROW_NUMBERの仕切り部のないソリューションです。

SELECT 
    a.city_start, a.city_end, b.city_end, a.date_start, b.date_start, 
    min(a.price + b.price) 
FROM 
    flight AS a 
    JOIN 
    flight AS b ON a.city_start = b.city_end AND a.city_end = b.city_start 
WHERE b.date_start BETWEEN a.date_start + 1 AND a.date_start + 20 
GROUP BY a.city_start, a.city_end, b.city_end, a.date_start, b.date_start; 
+0

これはまた大変感謝しています。一つの質問: 'group by'の外でプロパティを選択したいのですが?例えば ​​'a.carName'? – membersound

+0

データにcarNameが表示されないため、わかりません。私は質問の答えになることができるデータの残りの文脈でそれを見る必要があります... –

+0

もちろん質問は例を示しています。各行に 'carName'という列があると仮定してください。問題は、グループ内にない場合、どのようにしてこの値を選択できるのかです。 – membersound

0

追加の列を含める場合は、次を試してください。

SELECT 
    a.city_start, a.city_end, b.city_end, a.date_start, b.date_start, 
    a.price + b.price, a.car_name, b.car_name 
FROM 
    flight AS a 
    JOIN 
    flight AS b ON a.city_start = b.city_end AND a.city_end = b.city_start 
    LEFT JOIN 
    flight AS c ON 
     a.city_start = c.city_start 
     AND 
     a.city_end = c.city_end 
     AND 
     a.date_start = c.date_start 
     AND (
      a.price > c.price 
      OR (
       a.price = c.price 
       AND 
       a.id > c.id)) 
    LEFT JOIN 
    flight AS d ON 
     b.city_start = d.city_start 
     AND 
     b.city_end = d.city_end 
     AND 
     b.date_start = d.date_start 
     AND (
      b.price > d.price 
      OR (
       b.price = d.price 
       AND 
       b.id > d.id)) 
WHERE 
    b.date_start BETWEEN a.date_start + 1 AND a.date_start + 20 
    AND 
    c.id IS NULL 
    AND 
    d.id IS NULL; 
関連する問題