2

私はテーブルFooを持っています

FOO
-------
id
name

BAR
-------
id
name

FOO_BAR_XREF
-------
foo_id
bar_id

foo.id の foo_bar_xref に bar_id が 1 のレコードがある FOO のすべてのインスタンスを選択し、foo.id に bar_id が 2 のレコード n foo_bar_xref があるレコードを foo から除外する必要があります。

foo -> foo_bar_xref は 1 対多です *強調されたテキスト*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

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.id の foo_bar_xref に bar_id が 1 のレコードがある FOO のすべてのインスタンスを選択し、foo.id に bar_id が 2 のレコード n foo_bar_xref があるレコードを foo から除外する必要があります。

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

以下は、これを行う 1 つの方法です。これは、bar=1 であるが bar=2 ではない foo を取得するために、xref テーブルを要約します。一般に、このタイプのクエリには集計を使用することを好みます。

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 に答える