Как пересечь два запроса в MySQL - PullRequest
0 голосов
/ 30 мая 2019

У меня есть 3 таблицы в базе данных следующим образом:

airlines
+----+-----------------+-------+---------+ 
| Id | Name            | Abbr  | Country |
+----+-----------------+-------+---------+
| 1  | United Airlines | UAL   | USA     |
| 2  | US Airways      | USAir | USA     |
|... | ...             | ...   | ...     |
+----+-----------------+-------+---------+
airports
+--------------+------+-------------+---------------+-------+
| City         | Code | Name        | Country       | CAbbr |
+--------------+------+-------------+---------------+-------+
| Apalachicola | AAF  | Municipal   | United States | US    |
| Abilene      | ABI  | US Airways  | United States | US    |
| ...          | ...  | ...         | ...           | ...   |
+--------------+------+-------------+---------------+-------+
flights
+---------+----------+--------+-------------+
| Airline | FlightNo | Source | Destination |
+---------+----------+--------+-------------+
| 1       | 28       | APG    | ASY         |
| 1       | 44       | CVO    | ACV         |
| ...     | ...      | ...    | ...         |
+---------+----------+--------+-------------+

Я пытаюсь сообщить обо всех парах аэропортов, обслуживаемых Frontier и JetBlue. Каждая пара аэропортов должна быть сообщена ровно один раз (если сообщается о паре X, Y, тогда пара Y, X является избыточной и не должна сообщаться).

Мне кажется, я понимаю, как получить рейсы Frontier и JetBlue отдельно:

SELECT  ap1.Code, ap2.Code
FROM    flights f, airports ap1, airports ap2, airlines al
WHERE   ap1.Code = f.Source
AND     ap2.Code = f.Destination
AND     f.Airline = al.Id
AND     al.Abbr = 'Frontier'
ORDER BY ap1.Code ASC;

SELECT  ap1.Code, ap2.Code
FROM    flights f, airports ap1, airports ap2, airlines al
WHERE   ap1.Code = f.Source
AND     ap2.Code = f.Destination
AND     f.Airline = al.Id
AND     al.Abbr = 'JetBlue'
ORDER BY ap1.Code ASC;

Но я не понимаю, как получить Пересечение между ними. Я пробовал и LEFT JOIN, и WHERE EXISTS, но я делаю что-то не так, потому что я получаю то, что выглядит скорее как союз, чем пересечение. Вот моя последняя попытка (определенно ошибочная).

SELECT  ap1.Code, ap2.Code AS code
FROM    airports ap1, airports ap2
WHERE 
EXISTS (SELECT  ap1.Code, ap2.Code
        FROM    flights f, airports ap1, airports ap2, airlines al
        WHERE   ap1.Code = f.Source
        AND     ap2.Code = f.Destination
        AND     f.Airline = al.Id
        AND     al.Abbr = 'Frontier') AND
EXISTS (SELECT  ap1.Code, ap2.Code
        FROM    flights f, airports ap1, airports ap2, airlines al
        WHERE   ap1.Code = f.Source
        AND     ap2.Code = f.Destination
        AND     f.Airline = al.Id
        AND     al.Abbr = 'JetBlue')
ORDER BY ap1.Code ASC;

И как только пересечение будет найдено, я не совсем уверен, как сделать, чтобы пары X, Y и Y, X отличались друг от друга, потому что DISTINCT не распознает кортежи как одинаковые.

Любая помощь будет высоко ценится.

Ответы [ 2 ]

0 голосов
/ 30 мая 2019
SELECT apPairs.*, ap1.stuff, ap2.stuff
FROM (
   SELECT LEAST(f.Source, f.Destination) AS ap1Code
      , GREATEST(f.Source, f.Destination) AS ap2Code
   FROM airlines AS al
   INNER JOIN flights AS f ON al.Id = f.Airline
   WHERE al.Abbr IN ('Frontier', 'JetBlue')
   GROUP BY ap1Code, ap2Code
   HAVING COUNT(DISTINCT al.Abbr) = 2  -- Served by both airlines
) AS apPairs
INNER JOIN airports AS ap1 ON apPairs.ap1Code = ap1.Code
INNER JOIN airports AS ap2 ON apPairs.ap1Code = ap2.Code
;

Я использовал LEAST и GREATEST для объединения любых (X, Y) и (Y, X) избыточностей; эти функции специфичны для MySQL, поэтому в других RDBMS вам может потребоваться создать свои собственные версии этих функций. Примечание: в зависимости от того, как используются эти данные, вы можете дважды проверить предположение, что пары x-> y и y-> x действительно избыточны; Возможно (по крайней мере, на самом деле), что у авиакомпании может быть маршрут X-> Y-> Z-> X, но нет прямого Y-> X.

COUNT (DISTINCT) в предложении HAVING гарантирует, что каждый аббревиатура авиакомпании будет учитываться только один раз, поэтому 100 рейсов не будут увеличивать числа. Его использование в запросе гарантирует, что вы получите аэропорты, обслуживаемые обеими авиакомпаниями, а не либо авиакомпания.

Поскольку запрос в apPairs уже содержит коды, вам даже не нужно выполнять внешний запрос; но я добавил на тот случай, если вам нужна информация из таблицы аэропортов, которую вам не нужно указывать в вопросе.

0 голосов
/ 30 мая 2019

Если вам нужны оба варианта, то вы можете попробовать использовать IN для авиакомпаний

SELECT  ap1.Code, ap2.Code
FROM    flights f
INNER JOIN airports ap1 ON  ap1.Code = f.Source
INNER JOIN airports ap2 ON ap2.Code = f.Destination
INNER JOIN airlines al ON  f.Airline = al.Id
WHERE  al.Abbr IN ( 'Frontier', 'JetBlue')
ORDER BY ap1.Code ASC;

Вы должны избегать старого (1992) неявного синтаксиса объединения, основанного на где, и использовать явный синтаксис объединения

...