У меня есть таблица авиакомпании с идентификатором Пассажира, местами вылета и прилета.

+-------------+-----------+----------+
| PassengerID | Town_from | Town_to  |
+-------------+-----------+----------+
|           1 | London    | Valetta  |
|           1 | Valetta   | London   |
|           1 | Bangkok   | Hanoi    |
|           2 | Prague    | Vienna   |
|           2 | Vienna    | Prague   |
|           3 | Budapest  | Vilnius  |
|           4 | Moscow    | Helsinki |
|           4 | Helsinki  | Moscow   |
|           4 | Moscow    | Helsinki |
|           5 | Lyon      | Paris    |
|           5 | New York  | Toronto  |
+-------------+-----------+---------+

Я хочу найти пассажиров, которые проехали только один маршрут туда и обратно, чтобы результат выглядел так:

+-------------+-----------+----------+
| PassengerID | Town_from | Town_to  |
+-------------+-----------+----------+
|           2 | Prague    | Vienna   |
|           2 | Vienna    | Prague   |
|           4 | Moscow    | Helsinki |
|           4 | Helsinki  | Moscow   |
|           4 | Moscow    | Helsinki |
+-------------+-----------+---------+

Или вот так:

+-------------+
| PassengerID |
+-------------+
|           2 |
|           4 |
+-------------+

Почему это PassengerID:

1 - НЕТ, потому что есть 1 обратный рейс и 1 невозврат
2 - ДА, потому что есть только 1 пара
3 - НЕТ, потому что обратного пути нет (Бад - Виль, но не Виль - Бад)
4 - ДА, потому что есть еще 1 пара, хотя более 2 поездок
5 - НЕТ, потому что в эти пары нет обратных поездок

Я попробовал что-то вроде:

SELECT PassengerID FROM table
GROUP BY PassengerID
HAVING COUNT(DISTINCT town_from) = 2 AND COUNT(DISTINCT town_to) = 2

Но это также включает в себя совершенно разные места назначения (ID 5) для набора результатов. Я не могу понять, как я могу сравнить 2 столбца при их группировании.

3
Musisak 2 Сен 2017 в 15:20

5 ответов

Лучший ответ

Как обычно, в SQL есть несколько способов получить один и тот же результат с разными запросами ... Я выложу свой.

Вот рабочий SQLfiddle: http://sqlfiddle.com/#!9/385d3/1

Настройка данных

create table travel(PassengerID  varchar(64),Town_from  varchar(64),Town_to varchar(64));

insert into travel values('1','London','Valetta');
insert into travel values('1','Valetta','London');
insert into travel values('1','Bangkok','Hanoi');
insert into travel values('2','Prague','Vienna');
insert into travel values('2','Vienna','Prague');
insert into travel values('3','Budapest','Vilnius');
insert into travel values('4','Moscow','Helsinki');
insert into travel values('4','Helsinki','Moscow');
insert into travel values('4','Moscow','Helsinki');

И фактический запрос

SELECT DISTINCT PassengerID
FROM TRAVEL
WHERE NOT EXISTS (
  SELECT PassengerID 
  FROM TRAVEL a
  WHERE TRAVEL.PassengerID = a.PassengerID AND NOT EXISTS
   (SELECT * 
    FROM TRAVEL b
    WHERE a.PassengerID = b.PassengerID 
    AND a.Town_from = b.Town_to
    AND a.Town_to = b.Town_from
))

Самый внутренний запрос (FROM TRAVEL b) находит все обратные поездки относительно промежуточного запроса (FROM TRAVEL a).

Промежуточный запрос (FROM TRAVEL a) затем возвращает PassengerID всех пассажиров во всех поездках, которые НЕ имеют обратной поездки, используя условие NOT EXISTS.

Внешний запрос снова инвертирует результат, удаляя эти «несопоставимые» поездки из исходной таблицы.

2
Damiano 2 Сен 2017 в 13:46
DECLARE @FlightData TABLE (
    PassengerID INT,
    Town_from NVARCHAR(500),
    Town_to NVARCHAR(500)
)
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 1,'London','Valetta'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 1,'Valetta','London'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 1,'Bangkok','Hanoi'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 2,'Prague','Vienna'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 2,'Vienna','Prague'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 3,'Budapest','Vilnius'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 4,'Moscow','Helsinki'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 4,'Helsinki','Moscow'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 4,'Moscow','Helsinki'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 5,'Lyon','Paris'
INSERT INTO @FlightData(PassengerID,Town_from,Town_to) SELECT 5,'New York','Toronto'

SELECT *
FROM @FlightData
WHERE PassengerID NOT IN(
    SELECT
        fd1.PassengerID
    FROM @FlightData fd1
    LEFT JOIN @FlightData fd2 ON fd2.PassengerID=fd1.PassengerID
        AND fd2.Town_from=fd1.Town_to
        AND fd2.Town_to=fd1.Town_from
    WHERE fd2.PassengerID IS NULL
)
1
UnhandledExcepSean 2 Сен 2017 в 12:39
WITH CTE AS
(
select distinct trv1.PassengerID, 
trv1.town_from AS a, 
trv1.town_to AS b, 
trv2.town_from AS c, 
trv2.town_to AS d  
FROM travel trv1
LEFT JOIN travel trv2 ON trv1.PassengerID=trv2.PassengerID
AND trv1.town_from=trv2.town_to
AND trv1.town_to=trv2.town_from
ORDER BY trv1.PassengerID, trv1.town_from
), 

SCTE AS
(
SELECT *, row_number() over(partition by CTE.PassengerID) AS count
FROM CTE
),

SSCTE AS
(
SELECT *, sum(SCTE.count) over(partition by SCTE.PassengerID) AS sum
FROM SCTE
)

SELECT 
SSCTE.PassengerID, 
SSCTE.a, 
SSCTE.b
from SSCTE
WHERE SSCTE.sum = 3
ORDER BY SSCTE.PassengerID;
0
Newbie92 3 Сен 2017 в 07:10

Ваши данные и объяснения неоднозначны, так как вы исключаете ID 1, потому что у него две разные пары (хотя одна - туда и обратно, а другая - нет), но вы исключаете ID 5, потому что нет ни одного обратного рейса ни на один из рейсов на одной ноге, который указывает на этот ID 5 будет включен, если он будет иметь обратные рейсы, но ID 1 не будет включен, если был включен этап Ханой-Бангкок.

Включаете ли вы только идентификаторы, которые имеют одиночный из / в пару (но несколько поездок в порядке)? Это не ясно.

Это еще один пример, который даст желаемые результаты для идентификаторов 2 и 4 (однако он не включает идентификаторы, которые могли бы иметь несколько полных и разных циклов, если это было вашим намерением)

SELECT DISTINCT(t1.id) FROM Travel t1 JOIN Travel t2 ON (t1.id=t2.id AND 
t1.town_from=t2.town_to AND t1.town_from<>t2.town_from AND 
t1.town_to<>t2.town_to)
EXCEPT
SELECT DISTINCT(t1.id) FROM Travel t1 JOIN Travel t2 ON (t1.id=t2.id AND 
t1.town_from<>t2.town_to AND t1.town_from<>t2.town_from AND 
t1.town_to<>t2.town_to)

Первый запрос исключает идентификатор 3 (и тому подобное), поскольку он выбирает только идентификаторы, которые имеют хотя бы одну «обратную поездку». Второй запрос находит все идентификаторы, которые имеют неполные или разные поездки, и удаляет их.

0
Andrew B 2 Сен 2017 в 13:43