SQL:选择不包含特定值的组

时间:2018-04-28 16:47:21

标签: sql sql-server database

我使用Microsoft SQL Server Management Studio 2014,我有这3个表:

EMPLOYEES

EMPID | FIRSTNAME
  1   | JOHNNY
  2   | DWAYNE
  3   | TOM
  4   | CHRISTIAN
  5   | JACK
  6   | BRAD
  7   | ADAM
  8   | MATT
  9   | WILL
  10  | JIM

飞机

AID | NAME
 1  | BOEING 1
 2  | BOEING 2
 3  | BOEING 3
 4  | BOEING 4
 5  | AIRBUS 1
 6  | AIRBUS 2
 7  | LEARJET
 8  | DOUGLAS
 9  | JUMBO
 10 | ILYUSHIN

CERTIFIED

EMPID | AID
  1   |  1
  1   |  2
  1   |  3
  1   |  4
  4   |  2
  4   |  3
  7   |  1
  7   |  2
  7   |  5
  7   |  6
  8   |  7
  8   |  8
  8   |  9
  2   |  10
  2   |  1
  2   |  9
  3   |  10
  5   |  8
  5   |  9

概念是有10名员工和10架飞机。 CERTIFIED表确定哪个员工有权驾驶哪些飞机。但并非所有员工都是飞行员。我需要的是以某种方式选择所有未经认证使用波音的飞行员。我尝试但没有奏效的是:

SELECT DISTINCT FIRSTNAME
FROM EMPLOYEES
WHERE EMPID IN (SELECT EMPID
                FROM CERTIFIED
                WHERE AID NOT IN (SELECT AID FROM AIRCRAFTS WHERE NAME LIKE 'BOEING%'))

这给出了这些结果:

JACK
MATT
TOM
ADAM
DWAYNE

这是错误的,因为根据CERTIFIED表格,ADAM和DWAYNE有权驾驶至少一架波音公司。

任何帮助将不胜感激,提前谢谢!

3 个答案:

答案 0 :(得分:2)

尝试此查询...

SELECT employees.empid, Max(employees.firstname) AS FirstName 
FROM   certified 
       INNER JOIN employees ON employees.empid = certified.empid 
WHERE  certified.empid NOT IN (SELECT certified.empid 
                               FROM   certified 
                               INNER JOIN aircrafts ON aircrafts.aid = certified.aid 
                               WHERE  aircrafts.NAME LIKE 'BOEING%') 
GROUP  BY employees.empid 

演示:http://www.sqlfiddle.com/#!18/8f26d/27/0

结果

+-------+-----------+
| EMPID | FirstName |
+-------+-----------+
|     3 | TOM       |
|     5 | JACK      |
|     8 | MATT      |
+-------+-----------+

答案 1 :(得分:1)

我认为您的询问是给予任何经过非波音飞机认证的员工 - 这是一组微妙的人。

对于你的问题,我会选择not exists

select e.*
from employees e
where not exists (select 1
                  from certified c join
                       aircrafts a
                       on c.aid = a.aid
                  where e.empid = c.empid and a.name like '%BOEING%'
                 );

另一种方法 - 如果您只想要员工ID - 使用聚合和having

select e.empid, e.firstname
from employees e join
     certified c
     on e.empid = c.empid join
     aircrafts a
     on c.aid = a.aid
group by e.empid, e.firstname
having sum(case when a.name like '%BOEING%' then 1 else 0 end) = 0;

我碰巧喜欢这种方法,因为它很容易推广到其他条件 - 例如苍蝇波音但不是空客或苍蝇Learjet和赛斯纳。

答案 2 :(得分:1)

你应该使用经过波音公司认证并加入航空器的船舶中的NOT IN

SELECT DISTINCT FIRSTNAME
FROM EMPLOYEES
WHERE EMPID NOT IN (SELECT EMPID
                FROM CERTIFIED c 
                INNER JOIN AIRCRAFTS a ON on a.AID  = c.AID 
                WHERE a.NAME LIKE 'BOEING%')