Sql多个连接到同一个表包括和独占

时间:2013-01-14 01:16:31

标签: sql sql-server sql-server-2008

我有一张桌子Foo

FOO
-------
id
name

BAR
-------
id
name

FOO_BAR_XREF
-------
foo_id
bar_id

我需要选择FOO的所有实例,其中foo.id在foo_bar_xref中有一个bar_id为1的记录,并从foo中排除记录,其中foo.id的记录为n foo_bar_xref,bar_id为2

foo - > foo_bar_xref是一对多*强调文本* foo_bar_xref每个foo_id可能包含多个bar_id

仅使用连接是否可行,或者我需要在where子句中使用not exists语句吗?

到目前为止我已经

select f.name from FOO f
inner join FOO_BAR_XREF fb_1 on fb_1.foo_id = f.id
inner join FOO_BAR_XREF fb_2 on fb_2.foo_id = f.id

where fb_1.bar_id = 1 and fb_2.bar_id <> 2
group by f.name -- remove dupes - running on sql server and is paged with sql servers hackish over keyword where distinct doesn't work so well.

那不会过滤出有2个条的

的foo

这似乎有效,但我不确定它是最有效的

select f.name from FOO f
inner join FOO_BAR_XREF fb_1 on fb_1.foo_id = f.id and fb_1.bar_id = 1
left outer join FOO_BAR_XREF fb_2 on fb_2.foo_id = f.id and fb_2.bar_id = 2

where fb_2.bar_id is null
group by f.name -- remove dupes

4 个答案:

答案 0 :(得分:3)

重申我的评论,我认为OP有最好的解决方案。在这些场景中,我总是使用左连接进行优化。

select f.name 
from FOO f 
inner join FOO_BAR_XREF fb_1 
  on fb_1.foo_id = f.id and fb_1.bar_id = 1 
left outer join FOO_BAR_XREF fb_2 
  on fb_2.foo_id = f.id 
  and fb_2.bar_id = 2
where fb_2.bar_id is null
group by f.name

SQL Fiddle

BTW,我认为这是表扫描方面最有效的解决方案。检查执行计划,看看你发生了什么。

答案 1 :(得分:2)

  

我需要选择FOO的所有实例,其中foo.id有记录   bar_id为1的foo_bar_xref并从foo中排除记录   foo.id有一个记录n foo_bar_xref,bar_id为2

由于您使用的是SQL Server,因此您可以使用EXCEPT设置操作来执行此操作:

SELECT f.id, f.name 
FROM FOO f
INNER JOIN FOO_BAR_XREF fb_1 ON fb_1.foo_id = f.id
WHERE fb_1.bar_id = 1
EXCEPT 
SELECT f.id, f.name from FOO f
INNER JOIN FOO_BAR_XREF fb_1 ON fb_1.foo_id = f.id
WHERE fb_1.bar_id = 2;

答案 2 :(得分:1)

以下是一种方法。它总结了外部参照表,以获得foo与bar = 1但不是bar = 2。我更喜欢在这种类型的查询中使用聚合。

select f.*
from foo f join
     (select f.foo_id
      from foo_bar_xref
      group by f.foo_id
      having max(case when bar_id = 1 then 1 else 0 end) > 0 and -- has 1 bar
             max(case when bar_id = 2 then 1 else 0 end) = 0     -- no 2 bar
    ) fbx
    on f.id = fbx.foo_id

注意:此SQL未经过测试,因此可能存在语法错误。

答案 3 :(得分:0)

select * from foo join (
select foo_id from FOO_BAR_XREF where bar_id =1
except
select foo_id from FOO_BAR_XREF where bar_id =2
) X on id=foo_id