2

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

那不是过滤掉 bar 为 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

4 回答 4

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 小提琴

顺便说一句,我认为这是关于表扫描的最有效的解决方案。检查你的执行计划,看看你在做什么。

于 2013-01-14T01:32:19.483 回答
2

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

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

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;
于 2013-01-14T01:23:30.690 回答
1

以下是执行此操作的一种方法。它总结了外部参照表以获取 bar=1 但不是 bar=2 的 foo。一般来说,我更喜欢对这种类型的查询使用聚合。

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 未经测试,因此可能存在语法错误。

于 2013-01-14T01:21:58.953 回答
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
于 2013-01-15T06:41:20.477 回答