3

旅行の区間を保存するデータベースを作成したいと思います。各区間のFKは別のテーブルにあり、旅行IDがキー/一意になります。

例:「「東海岸ロードトリップ」:ボストン-> NYC、NYC->フィラデルフィア、フィラデルフィア->ボルチモア、ボルチモア-> DC、DC->ローリー」

後で、次のような実行クエリが必要です。

"Which trips contain the NYC -> Philly and Philly -> Baltimore legs?"

そのような旅行情報を効果的に保存する方法について、私は少し困惑しています。トリップ識別子キーとトリップレッグをプレーンテキスト列として保存することは、おそらく最も効率的なソリューションではありません。

これにアプローチする方法についてのヒントをいただければ幸いです。

4

4 に答える 4

2

かなりシンプルに聞こえます。

trip_id、おそらく「East Coast roadtrip」などのラベル、おそらく旅行に参加した日付、出発日時などの旅行テーブルが必要です。

都市(「ボストン」、「フィリー」など)や、各区間の始点と終点を格納するノードテーブルが必要になる場合があります。したがって、これにはnode_idとその名前またはラベルが含まれます。

旅行の各区間は2つのノードに参加します。trip_id、from_node_id、およびto_node_idを含むtrip_legテーブルが必要です。目的地への到着日時など、他の情報が必要になる場合があります。

  SELECT t.label
    FROM trips as t
    INNER JOIN trip_legs as x1  ON (t.trip_id = x1.trip_id)
    INNER JOIN trip_legs as x2  ON (t.trip_id = x2.trip_id 
                                AND x1.to_node_id = x2.from_node_id)
    WHERE x1.from_node_id IN (SELECT node_id FROM nodes WHERE name = "NYC")
      AND x1.to_node_id   IN (SELECT node_id FROM nodes WHERE name = "Philly")
      AND x2.to_node_id   IN (SELECT node_id FROM nodes WHERE name = "Baltimore")
于 2013-03-23T00:52:52.030 に答える
2

私は以下を作成します:

可能な各ロケーションとID値を含むロケーションテーブル

CREATE TABLE Location(
    LocationID int NOT NULL AUTO_INCREMENT,
    Location nchar(10) NOT NULL,
    PRIMARY KEY 
(LocationID) 
);

旅行の各区間を含む区間表。これには、ロケーションテーブルへの外部キーとして機能する出発地と目的地の両方のロケーションIDを持つレッグのIDがあります。

CREATE TABLE Leg(
    LegID int NOT NULL AUTO_INCREMENT,
    Origin int NOT NULL,
    Destination int NOT NULL,
PRIMARY KEY(LegID) 
);

FOREIGN KEY(Origin) REFERENCES Location(LocationID)

FOREIGN KEY(Destination) REFERENCES Location(LocationID)

旅行の各区間を含み、旅行IDと基本的な詳細である旅行テーブル:

CREATE TABLE Trip(
    TripID int NOT NULL AUTO_INCREMENT,
PRIMARY KEY (TripID)
);

TripIDとLegIDでTripとLegの詳細を結合するTripLegテーブル

CREATE TABLE TripLeg(
    LegID int NOT NULL,
    TripID int NOT NULL,
PRIMARY KEY (LegID ,TripID)
);

FOREIGN KEY(LegID) REFERENCES Leg(LegID)
FOREIGN KEY(TripID) REFERENCES Trip(TripID)

これにより、都市、個々の区間、または総旅行に基づいてクエリを実行できます。お役に立てれば。

于 2013-03-23T01:04:03.560 に答える
2

旅行が「1回限り」ではなく、事前に決められた路線で行われると仮定すると(1つの路線で複数の旅行が発生する可能性があります)、次のようなものが必要になります。

ここに画像の説明を入力してください

(1回限りの場合、LINEが旅行だと想像してください。)

LEGの構造に注意してください。

  • そのPKにはLEG_NOが含まれていますが、STOP_IDは含まれていません。LEG_NOは、指定された行の区間の順序を決定し、必要に応じて(たとえば、往復で)複数の区間が同じ停車地を通過できるようにします。
  • また、レッグには「開始」(「終了」ではない)ストップのみがあります。「前」(LEG_NOで定義)レッグが何であれ、次のレッグの開始ストップを決定します。このように、切断されたレッグを持つことはできません(つまり、前のレッグの終了ストップが次のレッグの開始ストップと一致しない場合)。

TRIPのPKには、(たとえば)START_DATE_TIMEの代わりにTRIP_NOが含まれているため、必要に応じて、同じ回線で複数のトリップを同時に開始できます。

例の「東海岸ロードトリップ」ラインの23番目のトリップは、次のように表すことができます。

TRIP: LINE_ID  TRIP_NO
      -------  -------
          100       23

LINE: LINE_ID  LINE_NAME
      -------  ---------
          100  'East coast roadtrip'

LEG:  LINE_ID  LEG_NO  STOP_ID
      -------  ------  -------
          100       1       55
          100       2       11
          100       3       66
          100       4       22
          100       5       44
          100       6       33

STOP: STOP_ID  STOP_NAME
      -------  ---------
           22  'Baltimore'
           11  'NYC'
           33  'Raleigh'
           66  'Philly'
           55  'Boston'
           44  'DC'

(注:接続をより明確に具体化するために、意図的に非連続番号を使用しました。)


このデータベース構造を使用すると、次のように、指定されたすべての停車地を通過した旅行を簡単に取得できます。

SELECT *
FROM TRIP
WHERE
    LINE_ID IN (
        SELECT LINE_ID
        FROM LEG JOIN STOP ON LEG.STOP_ID = STOP.STOP_ID
        WHERE STOP_NAME IN ('NYC', 'Philly', 'Baltimore')
        GROUP BY LINE_ID
        HAVING COUNT(DISTINCT STOP_ID) = 3
    )

(注:古いバージョンのMySQLでは、クエリオプティマイザがINで抱えていた問題のため、このクエリをJOINとして書き直したいと思うでしょう。)

ただし、これらの停車地をこの順序で通過し、間に「ギャップ」がない旅行を取得したい場合は、太ももが急いで毛むくじゃらになります。おそらく最善の策は、SQL(基本的にセットベース)の順序を確立してギャップを検出しようとするのではなく、上記のサブクエリの結果を取得してクライアント側で分析することです。

于 2013-03-23T12:51:08.293 に答える
1

と1対多の関係を持つtripテーブルを用意しlegます。脚には、への外部キーが含まtofromますlocation

SELECT次に、必要な数のからを実行しleg、それぞれが異なる名前としてエイリアス化され、すべてが同じであることを確認することで、クエリを実行できますtrip_id

多分次のようなものです:

SELECT
    trip.name
FROM
    trip
    INNER JOIN leg leg1 ON (trip.id = leg1.trip_id)
    INNER JOIN leg leg2 ON (trip.id = leg2.trip_id)
    INNER JOIN location location_from1 ON (
        location_from1.id = leg1.location_from_id
    )
    INNER JOIN location location_to1 ON (
        location_to1.id = leg1.location_to_id)
    )
    INNER JOIN location location_from2 ON (
        location_from2.id = leg2.location_from_id
    )
    INNER JOIN location location_to2 ON (
        location_to2.id = leg2.location_to_id
    )
WHERE
    location_from1.name = 'NYC'
    AND location_to1.name = 'Philly'
    AND location_from2.name = 'Philly'
    AND location_to2.name = 'Baltimore'

ただし、これらの追加のロケーション結合はすべてコストがかかるため、このクエリの前にさまざまなロケーションの主キーを検索してWHEREから、句をレッグテーブルに追加するだけで済みます。

于 2013-03-23T00:52:31.027 に答える