陷入“In clause”

时间:2017-10-07 19:03:05

标签: sql oracle

我有以下表格:

 create table passenger ( passenger_ID varchar ( 10 ) , passenger_name varchar ( 30 ) , passenger_city varchar ( 30 ) , primary key ( passenger_ID ) ) ;
    create table flight ( flight_number varchar ( 10 ) , departure_airport varchar ( 10), arrival_airport varchar ( 10 ) , primary key ( flight_number ) );

    create table seat ( 
    flight_number varchar ( 10 ),
    seat_number varchar ( 10 ),
    primary key(flight_number, seat_number),
    foreign key(flight_number) references flight);

    create table reservation(
        passenger_ID varchar ( 10 ) 
        flight_number varchar ( 10 ) , seat_number varchar ( 10 ) , 
    day date ,
        fare numeric(8,2),
    primary key (flight_number, seat_number,day),
    foreign key (flight_number, seat_number) references seat ) ,
    foreign key (passenger_ID) references passenger ;

我被困在这个问题中: 查找从“ALB”出发的预订航班(或多个航班)的每位乘客的身份证明,并且从未预订到达“ALB”的航班。对于此查询,请使用in子句或not in子句。

我写了这么多查询:

select a.passenger_id from 
reservation a 
where a.flight_number in (select b.flight_number from flight b where 
                                        b.departure_airport = 'ALB' 
                                    and b.arrival_airport <> 'ALB');

但是这个查询不正确。子查询返回与过滤条件匹配的所有航班号。但是主选择查询返回子查询返回的flight_number的所有乘客ID,即使该乘客的arrival_airport是ALB。

我的预订表:

 passenger_id   flight_number   seat_number day fare
2   A2  201 10/1/17 1083
1   A3  301 10/1/17 1173.25
1   A4  402 10/1/17 846.81
2   A5  501 10/1/17 752.72
1   A5  502 10/1/17 485
4   A5  506 10/1/17 970
2   A6  601 10/1/17 388
1   A7  703 10/1/17 921.5
3   A7  704 10/1/17 921.5
2   A8  804 10/1/17 970
4   A8  805 10/1/17 970

我的航班表:

flight_number   departure_airport   arrival_airport
A1  Ktm Pkr
A2  Ktm NY
A3  Ktm Ind
A4  Ktm Chn
A5  ALB KTM
A6  ALB PKR
A7  KTM ALB
A8  PKR ALB

3 个答案:

答案 0 :(得分:2)

思考:两个条件。所以从你的思路来看:

select r.passenger_id
from reservation r
where r.flight_number in (select f.flight_number
                          from flight f
                          where f.departure_airport = 'ALB' 
                         ) and
      r.flight_number not in (select f.flight_number
                              from flight f
                              where f.arrival_airport = 'ALB' 
                             );

然而,这不是那样做的。抵达ALB的任何航班都从其他机场出发。因此,这只是选择从ALB预订航班的所有乘客。此逻辑位于航班级别,而不是乘客级别。

Hmmmm。您实际上需要有关客户“一次性”所有航班的信息。这表明聚合:

select r.passenger_id
from reservation r join
     flight f
     on r.flight_number = f.flight_number
group by r.passenger_id
having sum(case when f.departure_airport = 'ALB' then 1 else 0 end) > 0 and -- reserved a flight from ALB
       sum(case when f.arrival_airport = 'ALB'  then 1 else 0 end) = 0;     -- never reserved a flight to ALB

答案 1 :(得分:1)

为了以稍微不同的方式证明@ GordonLinoff答案的正确性,让我们稍微看一下它。 :-)(See this SQLFiddle)。 (请注意,我填写了PASSENGER表。我们稍后会使用它。:-)。首先,让我们抓住所有预订至少一架从ALB起飞的航班的乘客:

-- Find passengers who have reserved at least one flight departing from ALB

SELECT DISTINCT r.PASSENGER_ID
  FROM RESERVATION r
  INNER JOIN FLIGHT f
    ON f.FLIGHT_NUMBER = r.FLIGHT_NUMBER
  WHERE f.DEPARTURE_AIRPORT = 'ALB';

这将返回PASSENGER_ID的1,2和4。

接下来,让我们找到至少有一班航班抵达ALB的所有乘客:

-- Find passengers who have reserved at least one flight arriving at ALB

SELECT DISTINCT r.PASSENGER_ID
  FROM RESERVATION r
  INNER JOIN FLIGHT f
    ON f.FLIGHT_NUMBER = r.FLIGHT_NUMBER
  WHERE f.ARRIVAL_AIRPORT = 'ALB';

这将返回PASSENGER_ID的1,2,3和4。

对上述结果进行的微不足道的检查清楚地表明,没有乘客预订了从ALB起飞的航班,他们没有预订到达ALB的航班。但是因为我们想让查询向我们展示我们想要的东西而不是必须思考(毕竟,这就是计算机应该做的事情:-)我们将把上述查询放在一起:

-- Now put them together

SELECT p.PASSENGER_ID
  FROM PASSENGER p
  INNER JOIN (SELECT DISTINCT r.PASSENGER_ID
                FROM RESERVATION r
                INNER JOIN FLIGHT f
                  ON f.FLIGHT_NUMBER = r.FLIGHT_NUMBER
                WHERE f.DEPARTURE_AIRPORT = 'ALB') d
    ON d.PASSENGER_ID = p.PASSENGER_ID
  LEFT OUTER JOIN (SELECT DISTINCT r.PASSENGER_ID
                     FROM RESERVATION r
                     INNER JOIN FLIGHT f
                       ON f.FLIGHT_NUMBER = r.FLIGHT_NUMBER
                     WHERE f.ARRIVAL_AIRPORT = 'ALB') a
    ON a.PASSENGER_ID = p.PASSENGER_ID
  WHERE a.PASSENGER_ID IS NULL;

此查询不会按预期返回任何结果。

但是......我们确实希望确保我们的查询确实有效。 Soooo ...让我们在几个表中添加几行。首先,我们将添加一名新乘客:

insert into passenger (passenger_ID, passenger_name, passenger_city)
  values ('5', 'Bugs Bunny', 'ABC');

我们将为Bunny先生添加一个航班,他将离开ALB:

INSERT INTO RESERVATION (PASSENGER_ID, FLIGHT_NUMBER, SEAT_NUMBER, DAY, FARE)
  VALUES ('5', 'A6', '123', TO_DATE('2017-10-01','YYYY-MM-DD'), 400);

所以现在我们有乘客5,B.Bunny先生,离开ALB - 但他从未飞入ALB。 (我想那是因为他应该在阿尔伯克基左转:-)。所以我们的查询应该返回乘客5,而if you go look at this SQLFiddle你会看到正是发生的事情。

嗯 - 祝你好运,医生。

答案 2 :(得分:1)

使用IN()NOT IN()

专注于乘客而不是航班
SELECT DISTINCT
      r.passenger_id
FROM reservation r
WHERE r.passenger_id IN (
      SELECT
            r.passenger_id
      FROM RESERVATION r
      INNER JOIN FLIGHT f ON f.flight_number  = r.flight_number 
      WHERE f.DEPARTURE_AIRPORT = 'ALB'
    )
AND r.passenger_id NOT IN (
      SELECT
            r.passenger_id
      FROM RESERVATION r
      INNER JOIN FLIGHT f ON f.flight_number  = r.flight_number 
      WHERE f.ARRIVAL_AIRPORT = 'ALB'
    )
;

但Bob Jarvis的分析确实显示样本数据中没有行符合分配标准。