Thread: JOIN a table twice for different values in the same query

JOIN a table twice for different values in the same query

From
Colin Wetherbee
Date:
Greetings.

I have two tables I'm having a little trouble figuring out how to JOIN.

One contains a list of airports along with their IATA codes, cities, 
names, and so forth.  This table also contains an id column, which is a 
serial primary key.

The other table contains a list of flights, each of which has a 
departure_port and an arrival_port, which are foreign keys referencing 
the id field of the first table.

I would like to construct a query on the flight table that returns the 
names of both the departure port and the arrival port.

The following query shows how I would get just the departure port.

js=# SELECT departure_date, jsports.code AS departure_code FROM
jsjourneys JOIN jsports ON jsjourneys.departure_port = jsports.id LIMIT
4;
 departure_date | departure_code
----------------+---------------- 2006-11-19     | ATL 2006-11-16     | ATL 2006-11-19     | BHM 2007-02-03     | BOS
(4 rows)

When I SELECT jsports.code, the result comes from the JOIN ... ON 
jsjourneys.departure_port = jsports.id.

I would *also* like to include something in the query to get the 
jsports.code for jsjourneys.arrival_port, but I'm unsure how to do this, 
since SELECTing jsports.code twice would be ambiguous (and, in any case, 
just duplicates the departure_code).

I'd like to produce a result set that looks something like the following 
(which doesn't come from a real query).
 departure_date | departure_code | arrival_code
----------------+----------------+-------------- 2006-11-19     | ATL            | JFK 2006-11-16     | ATL
|DFW 2006-11-19     | BHM            | IAH 2007-02-03     | BOS            | LAX
 

I'd appreciate some help.

FYI, table definitions for jsjourneys and jsports follow.

js=# \d jsjourneys                                        Table "public.jsjourneys"       Column        |
Type          |   Modifiers
 
---------------------+--------------------------+--------------------------------------------------------- id
      | bigint                   | not null default 
 
nextval('jsjourneys_id_seq'::regclass) userid              | bigint                   | not null typeid              |
integer                 | not null carrier             | integer                  | number              | integer
          | departure_port      | integer                  | not null arrival_port        | integer                  |
notnull departure_gate      | character varying        | arrival_gate        | character varying        |
departure_date     | date                     | not null fare_class          | integer                  |
scheduled_departure| timestamp with time zone | scheduled_arrival   | timestamp with time zone | actual_departure    |
timestampwith time zone | actual_arrival      | timestamp with time zone | equipment           | integer
 | notes               | character varying(1500)  | seat                | character varying(4)     | confirmation
| character varying(20)    |
 
Indexes:    "jsjourneys_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:    "jsjourneys_arrival_port_fkey" FOREIGN KEY (arrival_port) 
REFERENCES jsports(id)    "jsjourneys_carrier_fkey" FOREIGN KEY (carrier) REFERENCES 
jscarriers(id)    "jsjourneys_departure_port_fkey" FOREIGN KEY (departure_port) 
REFERENCES jsports(id)    "jsjourneys_equipment_fkey" FOREIGN KEY (equipment) REFERENCES 
jsequipment(id)    "jsjourneys_fare_class_fkey" FOREIGN KEY (fare_class) REFERENCES 
jsfareclasses(id)    "jsjourneys_typeid_fkey" FOREIGN KEY (typeid) REFERENCES 
jsjourneytypes(id)    "jsjourneys_userid_fkey" FOREIGN KEY (userid) REFERENCES jsusers(id)

js=# \d jsports                                Table "public.jsports"  Column   |       Type        |
  Modifiers 
 

-----------+-------------------+------------------------------------------------------ id        | integer           |
notnull default 
 
nextval('jsports_id_seq'::regclass) code      | character varying | not null city      | character varying | not null
full_city| character varying | not null name      | character varying |
 
Indexes:    "jsports_pkey" PRIMARY KEY, btree (id)    "jsports_index_city" btree (city)    "jsports_index_code" btree
(code)

Thanks!

Colin


Re: JOIN a table twice for different values in the same query

From
Paul Lambert
Date:
Colin Wetherbee wrote:
> Greetings.
> 
> I have two tables I'm having a little trouble figuring out how to JOIN.
> 
> One contains a list of airports along with their IATA codes, cities, 
> names, and so forth.  This table also contains an id column, which is a 
> serial primary key.
> 
> The other table contains a list of flights, each of which has a 
> departure_port and an arrival_port, which are foreign keys referencing 
> the id field of the first table.
> 
> I would like to construct a query on the flight table that returns the 
> names of both the departure port and the arrival port.
> 
> The following query shows how I would get just the departure port.
> 
> js=# SELECT departure_date, jsports.code AS departure_code FROM
> jsjourneys JOIN jsports ON jsjourneys.departure_port = jsports.id LIMIT
> 4;
> 
>  departure_date | departure_code
> ----------------+----------------
>  2006-11-19     | ATL
>  2006-11-16     | ATL
>  2006-11-19     | BHM
>  2007-02-03     | BOS
> (4 rows)
> 
> When I SELECT jsports.code, the result comes from the JOIN ... ON 
> jsjourneys.departure_port = jsports.id.
> 
> I would *also* like to include something in the query to get the 
> jsports.code for jsjourneys.arrival_port, but I'm unsure how to do this, 
> since SELECTing jsports.code twice would be ambiguous (and, in any case, 
> just duplicates the departure_code).
> 
> I'd like to produce a result set that looks something like the following 
> (which doesn't come from a real query).
> 
>  departure_date | departure_code | arrival_code
> ----------------+----------------+--------------
>  2006-11-19     | ATL            | JFK
>  2006-11-16     | ATL            | DFW
>  2006-11-19     | BHM            | IAH
>  2007-02-03     | BOS            | LAX
> 
> I'd appreciate some help.
> 
> FYI, table definitions for jsjourneys and jsports follow.
> 
> js=# \d jsjourneys
>                                         Table "public.jsjourneys"
>        Column        |           Type           |   Modifiers
> ---------------------+--------------------------+--------------------------------------------------------- 
> 
>  id                  | bigint                   | not null default 
> nextval('jsjourneys_id_seq'::regclass)
>  userid              | bigint                   | not null
>  typeid              | integer                  | not null
>  carrier             | integer                  |
>  number              | integer                  |
>  departure_port      | integer                  | not null
>  arrival_port        | integer                  | not null
>  departure_gate      | character varying        |
>  arrival_gate        | character varying        |
>  departure_date      | date                     | not null
>  fare_class          | integer                  |
>  scheduled_departure | timestamp with time zone |
>  scheduled_arrival   | timestamp with time zone |
>  actual_departure    | timestamp with time zone |
>  actual_arrival      | timestamp with time zone |
>  equipment           | integer                  |
>  notes               | character varying(1500)  |
>  seat                | character varying(4)     |
>  confirmation        | character varying(20)    |
> Indexes:
>     "jsjourneys_pkey" PRIMARY KEY, btree (id)
> Foreign-key constraints:
>     "jsjourneys_arrival_port_fkey" FOREIGN KEY (arrival_port) REFERENCES 
> jsports(id)
>     "jsjourneys_carrier_fkey" FOREIGN KEY (carrier) REFERENCES 
> jscarriers(id)
>     "jsjourneys_departure_port_fkey" FOREIGN KEY (departure_port) 
> REFERENCES jsports(id)
>     "jsjourneys_equipment_fkey" FOREIGN KEY (equipment) REFERENCES 
> jsequipment(id)
>     "jsjourneys_fare_class_fkey" FOREIGN KEY (fare_class) REFERENCES 
> jsfareclasses(id)
>     "jsjourneys_typeid_fkey" FOREIGN KEY (typeid) REFERENCES 
> jsjourneytypes(id)
>     "jsjourneys_userid_fkey" FOREIGN KEY (userid) REFERENCES jsusers(id)
> 
> js=# \d jsports
>                                 Table "public.jsports"
>   Column   |       Type        |                      Modifiers
> -----------+-------------------+------------------------------------------------------ 
> 
>  id        | integer           | not null default 
> nextval('jsports_id_seq'::regclass)
>  code      | character varying | not null
>  city      | character varying | not null
>  full_city | character varying | not null
>  name      | character varying |
> Indexes:
>     "jsports_pkey" PRIMARY KEY, btree (id)
>     "jsports_index_city" btree (city)
>     "jsports_index_code" btree (code)
> 
> Thanks!
> 
> Colin
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 4: Have you searched our list archives?
> 
>               http://archives.postgresql.org
> 

Try joining twice, something like:

SELECT departure_date,       dp.code AS departure_code,       ap.code AS arrival_code
FROM jsjourneys
JOIN jsports dp ON jsjourneys.departure_port = jsports.id
JOIN jsports ap ON jsjourneys.arrival_port=jsports.id


Re: JOIN a table twice for different values in the same query

From
"Daniel Hernandez"
Date:
js=# SELECT departure_date, departure.code AS departure_code, arrival.code as arraival_code<br />FROM jsjourneys <br
/>������ JOIN jsports as departure ON jsjourneys.departure_port = departure.id <br />��� �� JOIN jsports as arrival on
jsjourneys.arraival_port= arraival.id <br />LIMIT<br />4; <br /><br />Regards,<br /><br />Daniel Hern�ndez.<br />San
Diego,CA.<br />"The more you learn, more you earn".<br /><br /> --- On Thu 01/10, Colin Wetherbee <
cww@denterprises.org> wrote:<br /><blockquote style="border-left: 2px solid orange; padding-left: 7px; margin-left:
7px;"><b>From:</b>Colin Wetherbee [mailto: cww@denterprises.org]<br /><b>To: </b>pgsql-sql@postgresql.org<br /><b>Date:
</b>Thu,10 Jan 2008 17:07:00 -0500<br /><b>Subject: </b>[SQL] JOIN a table twice for different values in the same
query<br/><br />Greetings.<br /><br />I have two tables I'm having a little trouble figuring out how to JOIN.<br /><br
/>Onecontains a list of airports along with their IATA codes, cities, <br />names, and so forth. This table also
containsan id column, which is a <br />serial primary key.<br /><br />The other table contains a list of flights, each
ofwhich has a <br />departure_port and an arrival_port, which are foreign keys referencing <br />the id field of the
firsttable.<br /><br />I would like to construct a query on the flight table that returns the <br />names of both the
departureport and the arrival port.<br /><br />The following query shows how I would get just the departure port.<br
/><br/>js=# SELECT departure_date, jsports.code AS departure_code FROM<br />jsjourneys JOIN jsports ON
jsjourneys.departure_port= jsports.id LIMIT<br />4;<br /><br /> departure_date | departure_code<br
/>----------------+----------------<br/> 2006-11-19 | ATL<br /> 2006-11-16 | ATL<br /> 2006-11-19 | BHM<br />
2007-02-03| BOS<br />(4 rows)<br /><br />When I SELECT jsports.code, the result comes from the JOIN ... ON <br
/>jsjourneys.departure_port= jsports.id.<br /><br />I would *also* like to include something in the query to get the
<br/>jsports.code for jsjourneys.arrival_port, but I'm unsure how to do this, <br />since SELECTing jsports.code twice
wouldbe ambiguous (and, in any case, <br />just duplicates the departure_code).<br /><br />I'd like to produce a result
setthat looks something like the following <br />(which doesn't come from a real query).<br /><br /> departure_date |
departure_code| arrival_code<br />----------------+----------------+--------------<br /> 2006-11-19 | ATL | JFK<br />
2006-11-16| ATL | DFW<br /> 2006-11-19 | BHM | IAH<br /> 2007-02-03 | BOS | LAX<br /><br />I'd appreciate some help.<br
/><br/>FYI, table definitions for jsjourneys and jsports follow.<br /><br />js=# \d jsjourneys<br /> Table
"public.jsjourneys"<br/> Column | Type | <br /> Modifiers<br
/>---------------------+--------------------------+---------------------------------------------------------<br/> id |
bigint| not null default <br />nextval('jsjourneys_id_seq'::regclass)<br /> userid | bigint | not null<br /> typeid |
integer| not null<br /> carrier | integer |<br /> number | integer |<br /> departure_port | integer | not null<br />
arrival_port| integer | not null<br /> departure_gate | character varying |<br /> arrival_gate | character varying |<br
/>departure_date | date | not null<br /> fare_class | integer |<br /> scheduled_departure | timestamp with time zone
|<br/> scheduled_arrival | timestamp with time zone |<br /> actual_departure | timestamp with time zone |<br />
actual_arrival| timestamp with time zone |<br /> equipment | integer |<br /> notes | character varying(1500) |<br />
seat| character varying(4) |<br /> confirmation | character varying(20) |<br />Indexes:<br /> "jsjourneys_pkey" PRIMARY
KEY,btree (id)<br />Foreign-key constraints:<br /> "jsjourneys_arrival_port_fkey" FOREIGN KEY (arrival_port) <br
/>REFERENCESjsports(id)<br /> "jsjourneys_carrier_fkey" FOREIGN KEY (carrier) REFERENCES <br />jscarriers(id)<br />
"jsjourneys_departure_port_fkey"FOREIGN KEY (departure_port) <br />REFERENCES jsports(id)<br />
"jsjourneys_equipment_fkey"FOREIGN KEY (equipment) REFERENCES <br />jsequipment(id)<br /> "jsjourneys_fare_class_fkey"
FOREIGNKEY (fare_class) REFERENCES <br />jsfareclasses(id)<br /> "jsjourneys_typeid_fkey" FOREIGN KEY (typeid)
REFERENCES<br />jsjourneytypes(id)<br /> "jsjourneys_userid_fkey" FOREIGN KEY (userid) REFERENCES jsusers(id)<br /><br
/>js=#\d jsports<br /> Table "public.jsports"<br /> Column | Type | Modifiers <br /><br
/>-----------+-------------------+------------------------------------------------------<br/> id | integer | not null
default<br />nextval('jsports_id_seq'::regclass)<br /> code | character varying | not null<br /> city | character
varying| not null<br /> full_city | character varying | not null<br /> name | character varying |<br />Indexes:<br />
"jsports_pkey"PRIMARY KEY, btree (id)<br /> "jsports_index_city" btree (city)<br /> "jsports_index_code" btree
(code)<br/><br />Thanks!<br /><br />Colin<br /><br />---------------------------(end of
broadcast)---------------------------<br/>TIP 4: Have you searched our list archives?<br /><br />
http://archives.postgresql.org<br/></blockquote><p><hr /><font face="geneva" size="2"><b>Join Excite! - <a
href="http://www.excite.com"target="_blank">http://www.excite.com</a></b><br />The most personalized portal on the
Web!</font>

Re: JOIN a table twice for different values in the same query

From
Colin Wetherbee
Date:
Paul Lambert wrote:
> Colin Wetherbee wrote:
>> I would like to construct a query on the flight table that returns the 
>> names of both the departure port and the arrival port.
>>
>> The following query shows how I would get just the departure port.
>>
>> js=# SELECT departure_date, jsports.code AS departure_code FROM
>> jsjourneys JOIN jsports ON jsjourneys.departure_port = jsports.id LIMIT
>> 4;
>>
> Try joining twice, something like:
> 
> SELECT departure_date,
>        dp.code AS departure_code,
>        ap.code AS arrival_code
> FROM jsjourneys
> JOIN jsports dp ON jsjourneys.departure_port = jsports.id
> JOIN jsports ap ON jsjourneys.arrival_port=jsports.id
> 
> ---------------------------(end of broadcast)---------------------------
> TIP 6: explain analyze is your friend

Ah, I didn't realize you could alias tables inside the JOIN.  Excellent.  It works. :)

js=# SELECT departure_date, dp.code AS departure_code, ap.code AS 
arrival_code FROM jsjourneys JOIN jsports dp ON 
jsjourneys.departure_port = dp.id JOIN jsports ap ON 
jsjourneys.arrival_port = ap.id LIMIT 4;
 departure_date | departure_code | arrival_code
----------------+----------------+-------------- 2006-11-19     | BHM            | ATL 2006-11-16     | PIT
|ATL 2006-11-16     | ATL            | BHM 2006-10-26     | PIT            | BOS
 
(4 rows)

For archive completeness, note the query is joined relative to dp.id and 
ap.id, rather than jsports.id.

Thanks for your help!

Colin


Re: JOIN a table twice for different values in the same query

From
"Phillip Smith"
Date:
Try something like this where we alias the joined tables:

SELECT departure_date, j1.code AS departure_code, j2.code AS arrival_code
FROM jsjourneys
LEFT OUTER JOIN jsports AS j1 ON jsjourneys.departure_port = j1.id
LEFT OUTER JOIN jsports AS j2 ON jsjourneys.arrival_port = j2.id;

As a side note - all the IATA codes are unique for each airport - wouldn't
it be better to use these as the Primary Key and Foreign Keys? Then you
wouldn't have to even join the tables unless you wanted the port names (not
just the code)

Cheers,
~p


THINK BEFORE YOU PRINT - Save paper if you don't really need to print this

*******************Confidentiality and Privilege Notice*******************

The material contained in this message is privileged and confidential to
the addressee.  If you are not the addressee indicated in this message or
responsible for delivery of the message to such person, you may not copy
or deliver this message to anyone, and you should destroy it and kindly
notify the sender by reply email.

Information in this message that does not relate to the official business
of Weatherbeeta must be treated as neither given nor endorsed by Weatherbeeta.
Weatherbeeta, its employees, contractors or associates shall not be liable
for direct, indirect or consequential loss arising from transmission of this
message or any attachments
e-mail.


Re: JOIN a table twice for different values in the same query

From
Colin Wetherbee
Date:
Phillip Smith wrote:
> As a side note - all the IATA codes are unique for each airport -
> wouldn't it be better to use these as the Primary Key and Foreign
> Keys? Then you wouldn't have to even join the tables unless you
> wanted the port names (not just the code)

This is true, but FWIW, my application will mostly be joining for the 
name of the airport or the city, not the code.

I'll keep the idea of using the codes as keys in mind, though.  Thanks 
for pointing that out.

Colin



Re: JOIN a table twice for different values in the same query

From
Colin Wetherbee
Date:
Colin Wetherbee wrote:
> Phillip Smith wrote:
>> As a side note - all the IATA codes are unique for each airport -
>> wouldn't it be better to use these as the Primary Key and Foreign
>> Keys? Then you wouldn't have to even join the tables unless you
>> wanted the port names (not just the code)
> 
> This is true, but FWIW, my application will mostly be joining for the 
> name of the airport or the city, not the code.
> 
> I'll keep the idea of using the codes as keys in mind, though.  Thanks 
> for pointing that out.

Oh, now I remember why I'm using IDs as keys. ;)

The code isn't always going to be an airport, and, for example, a train 
station in Buenos Aires could conceivably have the same code as a 
shipping port in Rotterdam, which, in turn, might well be JFK. :)

Colin


Re: JOIN a table twice for different values in the same query

From
Magne Mæhre
Date:
Colin Wetherbee wrote:
> Colin Wetherbee wrote:
>> Phillip Smith wrote:
>>> As a side note - all the IATA codes are unique for each airport -
>>> wouldn't it be better to use these as the Primary Key and Foreign
>>> Keys? Then you wouldn't have to even join the tables unless you
>>> wanted the port names (not just the code)
>>
>> This is true, but FWIW, my application will mostly be joining for the 
>> name of the airport or the city, not the code.
>>
>> I'll keep the idea of using the codes as keys in mind, though.  Thanks 
>> for pointing that out.
> 
> Oh, now I remember why I'm using IDs as keys. ;)
> 
> The code isn't always going to be an airport, and, for example, a train 
> station in Buenos Aires could conceivably have the same code as a 
> shipping port in Rotterdam, which, in turn, might well be JFK. :)

Note that IATA codes are _NOT_ unique.   The current list of IATA 
trigrams list upward of 300 duplicate codes.  If you include the train 
stations, there might be additional collisions.

You could consider using the ICAO four-letter identifiers instead. They 
are unique, and are preferred by airspace management authorities.  A 
mapping to the corresponding IATA code exists.

--Magne


Re: JOIN a table twice for different values in the same query

From
Colin Wetherbee
Date:
Magne Mæhre wrote:
> Colin Wetherbee wrote:
>> Colin Wetherbee wrote:
>>> Phillip Smith wrote:
>>>> As a side note - all the IATA codes are unique for each airport -
>>>> wouldn't it be better to use these as the Primary Key and Foreign
>>>> Keys? Then you wouldn't have to even join the tables unless you
>>>> wanted the port names (not just the code)
>>>
>>> This is true, but FWIW, my application will mostly be joining for the 
>>> name of the airport or the city, not the code.
>>>
>>> I'll keep the idea of using the codes as keys in mind, though.  
>>> Thanks for pointing that out.
>>
>> Oh, now I remember why I'm using IDs as keys. ;)
>>
>> The code isn't always going to be an airport, and, for example, a 
>> train station in Buenos Aires could conceivably have the same code as 
>> a shipping port in Rotterdam, which, in turn, might well be JFK. :)
> 
> Note that IATA codes are _NOT_ unique.   The current list of IATA 
> trigrams list upward of 300 duplicate codes.  If you include the train 
> stations, there might be additional collisions.
> 
> You could consider using the ICAO four-letter identifiers instead. They 
> are unique, and are preferred by airspace management authorities.  A 
> mapping to the corresponding IATA code exists.

I have both ICAO and IATA codes in my database, but users who typically 
won't know (or even be aware of) ICAO codes will be using the front end.  In fact, in the front end, the users will see
somethinglike the 
 
following (with the respective, unique, application-specific port ID 
hidden in the background).

Houston, TX (IAH - George Bush Intercontinental Airport)
New York, NY (JFK - John F. Kennedy International Airport)
Dubai, United Arab Emirates (DXB - Dubai International Airport)

Which should be unique enough. :)

Colin