Comment faire un INNER JOIN sur plusieurs colonnes

168

Je travaille sur un projet de devoirs et je suis censé effectuer une requête de base de données qui trouve les vols soit par le nom de la ville, soit par le code de l'aéroport, mais la flightstable ne contient que les codes d'aéroport donc si je veux rechercher par ville, je dois rejoindre sur la airportstable.

Le tableau des aéroports comprend les colonnes suivantes: code, city
Le tableau des vols comprend les colonnes suivantes: airline, flt_no, fairport, tairport, depart, arrive, fare
Les colonnes fairportet tairportsont les codes d'aéroport de départ et d' arrivée.
Les colonnes departet arrivesont les dates de départ et d'arrivée.

Je suis venu avec une requête qui joint d'abord les vols sur la fairportcolonne et la airports.codecolonne. Pour que je corresponde au, tairportje dois effectuer une autre jointure sur les matchs précédents de la première jointure.

SELECT airline, flt_no, fairport, tairport, depart, arrive, fare
    FROM (SELECT * FROM flights
        INNER JOIN airports
        ON flights.fairport = airports.code
        WHERE (airports.code = '?' OR airports.city='?')) AS matches
    INNER JOIN airports
    ON matches.tairport = airports.code
    WHERE (airports.code = '?' OR airports.city = '?')

Ma requête renvoie les bons résultats et cela suffira pour les devoirs, mais je me demande si je peux JOINsur plusieurs colonnes? Comment pourrais-je construire la WHEREclause pour qu'elle corresponde au départ et à la ville / code de destination?

Ci-dessous, une "pseudo-requête" sur ce que je veux réaliser, mais je ne parviens pas à obtenir la syntaxe correctement et je ne sais pas comment représenter le airportstableau des départs et des destinations:

SELECT * FROM flights
INNER JOIN airports
ON flights.fairport = airports.code AND flights.tairport = airports.code
WHERE (airports.code = 'departureCode' OR airports.city= 'departureCity') 
    AND (airports.code = 'destinationCode' OR airports.city = 'destinationCity')

Mettre à jour

J'ai également trouvé que cette représentation visuelle des instructions SQL Join était très utile en tant que guide général sur la construction d'instructions SQL!

Kiril
la source
3
Astuce: Vous devez rechercher deux villes pour chaque enregistrement (une pour le fairport et l'autre pour le tairport. Il est donc OK (en effet nécessaire) d'avoir deux JOINs, avec la table des aéroports, mais l'un d'eux basé sur fairport l'autre sur tairport.
mjv
2
Indice 2: vous devrez donc également aliaser la table des aéroports pour savoir comment les différencier (c'est-à-dire quelle est la table des aéroports avec la recherche fairport et avec la recherche tairport). Le mot clé SQL pour l'alias est AS (bien qu'il puisse être omis, c'est-à-dire ... JOIN airports [AS] FA ON FA.code = vols.tairport ...)
mjv

Réponses:

141

Vous pouvez JOIN avec la même table plusieurs fois en donnant aux tables jointes un alias , comme dans l'exemple suivant:

SELECT 
    airline, flt_no, fairport, tairport, depart, arrive, fare
FROM 
    flights
INNER JOIN 
    airports from_port ON (from_port.code = flights.fairport)
INNER JOIN
    airports to_port ON (to_port.code = flights.tairport)
WHERE 
    from_port.code = '?' OR to_port.code = '?' OR airports.city='?'

Notez que to_portet from_portsont des alias pour les première et deuxième copies de la airportstable.

Daniel Vassallo
la source
OK, j'ai essayé la solution ci-dessus et je suis l'erreur suivante: Vous avez une erreur dans votre syntaxe SQL; Consultez le manuel correspondant à la version de votre serveur MySQL pour connaître la bonne syntaxe à utiliser près de 'INNER_JOIN airports to_port ON (to_port.code = vols.tairport) WHERE' à la ligne 7
Kiril
2
OH, je sais pourquoi :) c'est censé être INNER JOIN et non INNER_JOIN ... DOH!
Kiril
21
Si la table des aéroports est énorme, vaut-il mieux la rejoindre une seule fois à plusieurs conditions. Quelque chose comme - flights f INNER JOIN airports a ON a.code = f.fairport OR a.code = f.tairportVeuillez suggérer.
Ankur-m
26

quelque chose comme....

SELECT f.*
      ,a1.city as from
      ,a2.city as to
FROM flights f
INNER JOIN airports a1
ON f.fairport = a1. code
INNER JOIN airports a2
ON f.tairport = a2. code
Paul Creasey
la source
1
Je l'ai posé ci-dessus, je vais le poser ici aussi - Si la table des aéroports est énorme (ET il y a plus de filtre pour toute la requête en utilisant la condition WHERE), est-il préférable de la joindre une seule fois à plusieurs conditions. Quelque chose comme - flights f INNER JOIN airports a ON a.code = f.fairport OR a.code = f.tairportCela fait-il une différence? Qu'est-ce que tu penses?
Ankur-m
1
Cela fait une différence dans les résultats, le premier produit une ligne par vol avec de et vers, votre suggestion produirait 2 lignes par vol, une ligne avec le de et une avec l'aéroport de destination. Ce serait plus rapide de ne rejoindre qu'une seule fois.
Paul Creasey
19

si mysql vous convient:

SELECT flights.*, 
       fromairports.city as fromCity, 
       toairports.city as toCity
FROM flights
LEFT JOIN (airports as fromairports, airports as toairports)
ON (fromairports.code=flights.fairport AND toairports.code=flights.tairport )
WHERE flights.fairport = '?' OR fromairports.city = '?'

edit: exemple ajouté pour filtrer la sortie pour le code ou la ville

Phil Rykoff
la source
11

Pouvez-vous simplement utiliser et dans l'article sur?

Par exemple, quelque chose comme:

SELECT 
   airline, flt_no, fairport, tairport, depart, arrive, fare
FROM 
   flights
INNER JOIN 
   airports from_port ON (from_port.code = flights.fairport)
   and (to_port.code = flights.tairport)
ez33
la source
5
Comment diable cela est-il arrivé à 14 votes positifs? La déclaration est incorrecte à la fois dans la syntaxe et la signification.
ultracrepidarian
3

Si vous souhaitez effectuer une recherche sur les aéroports FROM et TO, vous souhaiterez vous joindre deux fois à la table Airports.Vous pouvez alors utiliser à la fois les tables from et to dans votre ensemble de résultats:

SELECT
   Flights.*,fromAirports.*,toAirports.*
FROM
   Flights
INNER JOIN 
   Airports fromAirports on Flights.fairport = fromAirports.code
INNER JOIN 
   Airports toAirports on Flights.tairport = toAirports.code
WHERE
 ...
Monsieur Zimbu
la source