我有一张桌子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
答案 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
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