识别两列中的相同对

时间:2017-09-02 12:20:33

标签: sql database

我有一张航空公司的桌子,上面有乘客识别器,他们的出发和到达目的地。

+-------------+-----------+----------+
| 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 - 不,因为没有回程(Bud - Vil但不是Vil - Bud)
4 - 是因为虽然超过2次行程仍然有1对 5 - 否,因为这些对没有回程

我尝试过类似的事情:

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

但是,这也包括与结果集完全不同的目的地(ID 5)。我无法弄清楚如何在分组时比较2列。

5 个答案:

答案 0 :(得分:2)

与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)然后使用NOT EXISTS条款返回所有没有回程的旅行中的所有乘客的PassengerID。

外部查询再次反转结果,从初始表中删除这些“不匹配”的行程。

答案 1 :(得分:1)

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
)

答案 2 :(得分:0)

你的数据和解释是模棱两可的,因为你消除了ID 1,因为它有两个不同的对(虽然一个是往返而一个不是),但你消除了ID 5,因为没有返回到一条腿的任何一条如果航班有回程,则表明将包括ID 5,但如果包括河内至曼谷航段则不会出现ID 1。

您是否只包含来自/来自的ID(但多次出行都可以)?目前尚不清楚。

这是另一个能够产生你想要的ID 2和4结果的例子(但是如果那是你的意图,它不包括任何可能有多次完整和不同往返的ID)

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)

第一个查询消除了ID 3(等等),因为它只选择至少有一个“往返”的ID。第二个查询查找所有具有非完整或不同行程的ID,并将其删除。

答案 3 :(得分:0)

另一种方式:

select distinct t1.PassengerID
from
    travel t1
    inner join travel t2
        on t1.PassengerID = t2.PassengerID AND
           t1.Town_from = t2.Town_to AND
           t1.Town_to = t2.Town_from
where
    (SELECT COUNT(*)
     FROM (SELECT DISTINCT PassengerID, Town_from, Town_to
           FROM travel t3
           WHERE t3.PassengerID = t1.PassengerID) temp
    ) = 2

http://sqlfiddle.com/#!6/6ed3a/4

答案 4 :(得分:0)

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;