代表'不在'子查询作为连接

时间:2014-07-30 20:26:09

标签: sql oracle join

我正在尝试转换以下查询:

select *
from employees
where emp_id not in (select distinct emp_id from managers);

到我将​​子查询表示为连接的表单中。我试过了:

select *
from employees a, (select distinct emp_id from managers) b
where a.emp_id!=b.emp_id;

我也尝试过:

select *
from employees a, (select distinct emp_id from managers) b
where a.emp_id not in b.emp_id;

但它没有给出相同的结果。我已经尝试了“内部加入”#39;语法也是如此,但无济于事。我对这个看似简单的问题感到沮丧。任何帮助将不胜感激。

6 个答案:

答案 0 :(得分:2)

假设员工数据集

Emp_ID
1
2
3
4
5
6
7

假设Manger数据集

Emp_ID
1
2
3
4
5
8
9

select *
from employees
where emp_id not in (select distinct emp_id from managers);

上面没有加入表格所以没有生成笛卡尔积...你只有7条记录...

以上会导致6和7为什么?员工数据中只有6和7不在经理表中。管理员中的8,9被忽略,因为您只返回员工的数据。

select *
from employees a, (select distinct emp_id from managers) b
where a.emp_id!=b.emp_id;

以上没有工作,因为生成了笛卡尔积...所有员工都是经理(假设每张表中7条记录7 * 7 = 49) 所以不要像在第一个查询中一样评估员工数据。现在,您还要评估所有员工的所有经理

所以选择*结果

1,1
1,2
1,3
1,4
1,5
1,8
1,9
2,1
2,2... 

更少where子句匹配... 所以7 * 7-7或42.虽然这可能是生命世界及其中所有东西的答案,但这不是你想要的。

我也尝试过:

select *
from employees a, (select distinct emp_id from managers) b
where a.emp_id not in b.emp_id;

再一次笛卡尔......所有员工都是所有经理

所以这就是左连接工作的原因

SELECT e.*
FROM employees e
LEFT OUTER JOIN managers m
  on e.emp_id = m.emp_id
WHERE m.emp_id is null

这首先表示加入ID ...所以不要生成笛卡尔,而是实际加入一个值来限制结果。但由于它是LEFT连接,因此从LEFT表(员工)返回一切,只返回与经理匹配的那些。

因此在我们的示例中将返回为e.emp_Di = m.Emp_ID

1,1
2,2
3,3
4,4
5,5
6,NULL
7,NULL

现在是where子句所以

6,Null
7,NULL are retained...

旧的ansii左连接的SQL标准在where子句中是* =

select *
from employees a, managers b
where a.emp_id *= b.emp_id  --I never remember if the * is the LEFT so it may be =*
and b.emp_ID is null;  

但是我发现这种符号更难以阅读,因为联接可以与其他限制标准混在一起......

答案 1 :(得分:1)

试试这个:

select e.*
from employees e
left join managers m on e.emp_id = m.emp_id
where m.emp_id is null

这将加入两个表。然后我们丢弃我们找到匹配经理的所有行,并留下不是经理的员工。

答案 2 :(得分:1)

使用Left Outer Join代替

select e.*
from employees e
left outer join managers m
on e.emp_id = m.emp_id
where m.emp_id is null

左外连接将保留m表中的行,即使它们没有基于e字段的匹配i emp_id表。我们在where m.emp_id is null上过滤 - 给我em表中没有匹配记录的所有行。 关于这个问题的更多内容可以在这里找到:

Visual representation of joins

from employees a, (select distinct emp_id from managers) b隐含cross join - 表之间的所有可能组合(而您需要left outer join

答案 3 :(得分:1)

你最好的选择可能是左联盟:

select
    e.*
from employees e
left join managers m on e.emp_id = m.emp_id
where
m.emp_id is null;

这里的想法是你要说你要从员工中选择所有内容,包括基于emp_id在管理器表中匹配的所有内容,然后过滤出实际上在manager表中有某些内容的行。

答案 4 :(得分:0)

MINUS关键字应该可以解决问题:

SELECT e.* FROM employees e
MINUS
Select m.* FROM managers m

希望有帮助...

答案 5 :(得分:0)

select *
from employees
where Not (emp_id in (select distinct emp_id from managers));