SQL选择一列的值在另一个条件列中是通用的行

Mac*_*iek 14 sql relational

我有一个交叉引用表,如下所示:

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
Run Code Online (Sandbox Code Playgroud)

它将文档与主题相匹配.文件可以是多个主题的成员.我想返回此表中的行,其中给定的文档与给定集合中的所有主题匹配.例如,给定一组主题:

(17,76)

我想只返回与交叉引用表中某处的所有主题(至少)匹配的文档的行.给定上述设置的期望输出集将是:

id  document_id  subject_id
2   5            17
3   5            76
5   9            17
6   9            76
Run Code Online (Sandbox Code Playgroud)

请注意,不返回表的最后一行,因为该文档仅匹配其中一个必需主题.

在SQL中查询此内容的最简单,最有效的方法是什么?

Ale*_*lis 28

我假设这个表的natrual键是document_id + subject_id,而id是一个代理; IOW,document_id和subject_id是唯一的.因此,我只是假装它不存在,并且自然键上有一个独特的约束.

让我们从明显的开始.

SELECT document_id, subject_id
  FROM document_subjects
 WHERE subject_id IN (17,76)
Run Code Online (Sandbox Code Playgroud)

这可以获得你想要的一切以及你不想要的东西.所以我们需要做的就是过滤掉其他东西."其他东西"是具有不等于所需主题的计数的计数的行组.

SELECT document_id
  FROM document_subjects
 WHERE subject_id IN (17,76)
 GROUP BY document_id
HAVING COUNT(*) = 2
Run Code Online (Sandbox Code Playgroud)

请注意,subject_id已删除,因为它不参与分组.更进一步,我将添加一个名为subjects_i_want的虚构表,其中包含您想要的N行主题.

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)
Run Code Online (Sandbox Code Playgroud)

显然,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))
Run Code Online (Sandbox Code Playgroud)

管他呢.