1

私が選択した任意の都市から出発して、ちょうど 1 つの他の都市に立ち寄った後に到達できるすべての都市をリストする必要があります。そして、最終都市と中間都市までの距離をリストします。

データベース内のテーブルは、次の属性を持つ都市で構成されています。

| city_id |   name    |  
  1         Edinburgh  
  2         Newcastle  
  3         Manchester

都市ペア:

| citypair_id | city_id |  
  1             1  
  1             2  
  2             1    
  2             3  
  3             2  
  3             3

と距離:

| citypair_id | distance |
  1             1234
  2             1324
  3             1324

および列車:

| train_id | departure_city_id | destination_city_id |
  1          1                   2
  2          2                   3
  3          1                   3
  4          3                   2

私はデータを何も入れていませんが、基本的に、city.name が私によってランダムに選択された場合、別の都市を経由する場合 (つまり、2 つの旅)、この都市からどの都市に到達できるかを調べる必要があります。次に、最終都市と中間都市までの距離。

目的のテーブルを返すクエリをどのように作成しますか?


データと不足しているテーブルを含めるように編集されました! 例として、エジンバラ(1)からニューカッスル(2)経由でマンチェスター(3)に行くことができ、エジンバラからマンチェスター経由でニューカッスルに行くことはできますが、マンチェスターからニューカッスル経由でエジンバラに行くことはできません(列車は3から出発するため)。 、2 に到着しますが、2 からの列車は 1 に到着しません)。このルートはクエリから返されるべきではありません。事前に混乱をお詫び申し上げます。

4

2 に答える 2

1

すべての宛先のツリーを構築するCTEがあります。

WITH RECURSIVE trip AS (
  SELECT c.city_id AS start_city,
    ARRAY[c.city_id] AS route,
    cast(c.name AS varchar(100)) AS route_text,
    c.city_id AS leg_start_city,
    c.city_id AS leg_end_city,
    0 AS trip_count,
    0 AS leg_length,
    0 AS total_length
  FROM cities c
UNION ALL
  SELECT
    trip.start_city,
    trip.route || t.destination_city_id,
    cast(trip.route_text || ',' || c.name AS varchar(100)),
    t.departure_city_id,
    t.destination_city_id,
    trip.trip_count + 1,
    d.distance,
    trip.total_length + d.distance
  FROM trains t
  INNER JOIN trip
    ON t.departure_city_id =  trip.leg_end_city
  INNER JOIN citypairs cps
    ON t.departure_city_id = cps.city_id
  INNER JOIN citypairs cpe
    ON t.destination_city_id = cpe.city_id AND
       cpe.citypair_id = cps.citypair_id
  INNER JOIN distances d
    ON cps.citypair_id = d.citypair_id
  INNER JOIN cities c
     ON t.destination_city_id = c.city_id
  WHERE NOT (array[t.destination_city_id] <@ trip.route))
SELECT *
FROM trip
WHERE trip_count = 2
AND start_city = (SELECT city_id FROM cities WHERE name = 'Edinburgh');

CTEは、各都市(開始時の非再帰部分)から開始し、次に、移動できるすべての宛先都市を決定します。行ったことのあるすべての都市を配列(ルート列)で追跡するため、再びループバックすることはありません。進行するにつれて、全体の移動距離と乗車した列車の数(trip_count)を追跡します。

それがツリーを通過するとき、それは距離の現在の合計を維持します。

これにより、

| START_CITY | ROUTE |                     ROUTE_TEXT | LEG_START_CITY | LEG_END_CITY | TRIP_COUNT | LEG_LENGTH | TOTAL_LENGTH |
--------------------------------------------------------------------------------------------------------------------------------
|          1 | 1,2,3 | Edinburgh,Newcastle,Manchester |              2 |            3 |          2 |       1324 |         2558 |
|          1 | 1,3,2 | Edinburgh,Manchester,Newcastle |              3 |            2 |          2 |       1324 |         2648 |

最後のWHERE句を削除すると、データ内のすべての可能な旅行が表示されます。同様に、trip_countを変更して、すべての単一の列車の目的地などを検索できます。

| START_CITY | ROUTE |                     ROUTE_TEXT | LEG_START_CITY | LEG_END_CITY | TRIP_COUNT | LEG_LENGTH | TOTAL_LENGTH |
--------------------------------------------------------------------------------------------------------------------------------
|          1 |     1 |                      Edinburgh |              1 |            1 |          0 |          0 |            0 |
|          2 |     2 |                      Newcastle |              2 |            2 |          0 |          0 |            0 |
|          3 |     3 |                     Manchester |              3 |            3 |          0 |          0 |            0 |
|          1 |   1,2 |            Edinburgh,Newcastle |              1 |            2 |          1 |       1234 |         1234 |
|          1 |   1,3 |           Edinburgh,Manchester |              1 |            3 |          1 |       1324 |         1324 |
|          2 |   2,3 |           Newcastle,Manchester |              2 |            3 |          1 |       1324 |         1324 |
|          3 |   3,2 |           Manchester,Newcastle |              3 |            2 |          1 |       1324 |         1324 |
|          1 | 1,2,3 | Edinburgh,Newcastle,Manchester |              2 |            3 |          2 |       1324 |         2558 |
|          1 | 1,3,2 | Edinburgh,Manchester,Newcastle |              3 |            2 |          2 |       1324 |         2648 |

cast(... as varchar(100))は少しハッキーで、なぜそれが必要なのかわかりませんが、それを回避する機会はまだありません。

SQLはテスト用にここにあります: http ://sqlfiddle.com/#!1/93964/24

于 2013-03-13T16:57:42.197 に答える
0

最初の部分は簡単です:

SELECT c2.name
FROM cities AS c
JOIN trains t ON c.city_id=t.departure_city_id
JOIN trains t2 ON t.destination_city_id=t2.departure_city_id
JOIN cities AS c2 ON t2.destination_city_id=c2.city_id
WHERE c2.city_id!=c.city_id
AND c.name='Edinburgh';

http://sqlfiddle.com/#!12/a656f/14 PG 9.1+ では、間にある任意の数の都市に対して再帰 CTE を使用して実行することもできました。距離はもう少し複雑で、city_pairs を実際のペアに変換した方がよいでしょう。

于 2013-03-11T21:22:14.090 に答える