14

次のような相互参照テーブルがあります。

id  document_id  subject_id
1   8            21
2   5            17
3   5            76
4   7            88
5   9            17
6   9            76
7   2            76

ドキュメントとサブジェクトを照合します。ドキュメントは、複数のサブジェクトのメンバーになることができます。特定のドキュメントが特定のセット内のすべてのサブジェクトと一致するこのテーブルから行を返したいと考えています。たとえば、被験者のセットが与えられた場合:

(17,76)

相互参照テーブルのどこかで、(少なくとも) そのセットのすべてのサブジェクトに一致するドキュメントの行のみを返したいと考えています。上記のセットが与えられた場合、望ましい出力セットは次のようになります。

id  document_id  subject_id
2   5            17
3   5            76
5   9            17
6   9            76

テーブルの最後の行は返されないことに注意してください。これは、ドキュメントが必要な件名の 1 つにしか一致しないためです。

SQLでこれを照会する最も簡単で効率的な方法は何ですか?

4

4 に答える 4

29

このテーブルの自然なキーは document_id + subject_id であり、その id はサロゲートであると想定しています。IOW、document_id、および subject_id は一意です。そのため、存在しないふりをして、一意の制約が自然キーにあるとします。

明白なことから始めましょう。

SELECT document_id, subject_id
  FROM document_subjects
 WHERE subject_id IN (17,76)

これにより、必要なものすべてと不要なものが得られます。したがって、他のものを除外するだけです。「その他のもの」は、目的の被験者の数と等しくない数を持つ行のグループです。

SELECT document_id
  FROM document_subjects
 WHERE subject_id IN (17,76)
 GROUP BY document_id
HAVING COUNT(*) = 2

グループ化に参加しないため、subject_id が削除されていることに注意してください。これをさらに一歩進めて、必要な科目の N 行を含む subject_i_want という架空のテーブルを追加します。

SELECT document_id
  FROM document_subjects
 WHERE subject_id IN (SELECT subject_id FROM subjects_i_want)
 GROUP BY document_id
HAVING COUNT(*) = (SELECT COUNT(*) FROM subjects_i_want)

明らかに subject_i_want は、別のサブクエリ、一時テーブルなどに交換できます。ただし、この document_id のリストを取得すると、より大きなクエリのサブセレクト内で使用できます。

SELECT document_id, subject_id, ...
  FROM document_subjects
 WHERE document_id IN(
        SELECT document_id
          FROM document_subjects
          WHERE subject_id IN (SELECT subject_id FROM subjects_i_want)
          GROUP BY document_id
         HAVING COUNT(*) = (SELECT COUNT(*) FROM subjects_i_want))

または何でも。

于 2009-09-10T23:16:24.753 に答える
2

Oracle (または with 節を使用できる任意のデータベース) を使用する。これにより、subject_id 値を 1 回だけ定義できます。

with t as (select distinct document_id from table1 where subject_id in (17,76) )
select document_id from table1 where subject_id in (select subject_id from t)
group by document_id 
having count(*) = (select count (*) from t);
于 2015-06-09T20:04:31.347 に答える
1

とても興味深い質問です。

より一般化されたクエリが必要であると想定していますが、これは、常に同じ数のサブジェクト (たとえば 2 つ) がある場合に私が行うことです。

 SELECT T.id, T.document_id, T.subject_id
   FROM table T
        INNER JOIN table T1 ON T.document_id = T1.document_id AND T1.subject_ID = 17
        INNER JOIN table T2 ON T.document_id = T2.document_id AND T2.subject_ID = 76            

もちろん、別のサブジェクト ID を追加するために、さらに別の INNER JOIN を追加することもできます。

于 2009-09-10T23:04:25.093 に答える
0
select document_id from table1
 where subject_id in (17, 76)
 group by document_id
having count(distinct subject_id) = 2
于 2009-09-10T23:15:48.873 に答える