Mysql 使用多对多相同类型关系表排除SELECT上的类似行

Mysql 使用多对多相同类型关系表排除SELECT上的类似行,mysql,sql,Mysql,Sql,我有两个MySQL表:Articles和SimilarArticles CREATE TABLE `Articles` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `text` text, `priority` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) CREATE TABLE `SimilarArticles` ( `article_id` int(11) unsigned

我有两个MySQL表:
Articles
SimilarArticles

CREATE TABLE `Articles` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `text` text,
  `priority` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
)

CREATE TABLE `SimilarArticles` (
  `article_id` int(11) unsigned NOT NULL,
  `similar_article_id` unsigned NOT NULL,
  PRIMARY KEY (`article_id`,`similar_article_id`)
)
SimilarArticles
是一个简单的关系表,用于跟踪相似的文章记录

中的用户totymedli很好地解释了如何在此场景中选择类似的记录,效果很好

但是现在我必须创建一个SELECT语句,确保结果中没有类似的文章。因此,对于表中所有类似文章的组,只有字段<代码>优先级中值最高的记录才能进入结果集

到目前为止,我还没有找到解决这个问题的方法。有人知道如何在MySQL中高效地实现这一点吗

例子: 表格文章

id     text      priority

1      FooA      1
2      Bar       1
3      FooB      3
4      FooC      2
5      Baz       9
article_id  similar_article_id

1           3
4           1
3           4
表格类似文章

id     text      priority

1      FooA      1
2      Bar       1
3      FooB      3
4      FooC      2
5      Baz       9
article_id  similar_article_id

1           3
4           1
3           4
我尝试创建的SELECT语句应返回:

id     text      priority

2      Bar       1
3      FooB      3
5      Baz       9

由于FooA、FooB和FooC在
SimilarArticles
表中是相似的,并且FooB在这三条记录中具有最高的
优先级
,因此结果集中应该只有FooB(以及没有相似记录的Bar和Baz)。

您需要进行左连接并过滤掉任何类似的文章。请参见SO创始人Jeff Atwood关于排除使用左联接的介绍

如果您还希望获得与类似文章无关的最高优先级文章,则必须将此查询与该查询合并:

    SELECT *
      FROM Articles
 LEFT JOIN SimilarArticles ON Articles.id = SimilarArticles.article_id
     WHERE SimilarArticles.article_id IS NULL

 UNION ALL

    SELECT Articles.*
      FROM Articles
INNER JOIN SimilarArticles ON Articles.id = SimilarArticles.article_id
INNER JOIN (SELECT max(priority) AS priority FROM SimilarArticles) maxp 
           ON maxp.priority = Articles.priority
     WHERE SimilarArticles.article_id IS NOT NULL

注意:联合后的第二个查询将返回所有具有最高优先级的记录,而不仅仅是第一个。如果您真的只想返回第一个,那么您必须在该查询的末尾添加
LIMIT 0,1

我找到的一个有效解决方案是创建一个查询,该查询为我提供了在额外列中分隔的每个文章逗号的所有类似文章ID

在使用服务器端语言对结果进行迭代时,我分解了类似的文章ID,并构建了一个包含所有类似ID的数组。这使我能够跳过ID已存储在该数组中的所有行

虽然我更喜欢纯SQL的解决方案,但我认为这在我的情况下运行得相当好

查询: 结果(使用给定的样本数据):
id类似\u id文本优先级
1 3,4 FooA 3

你有点自相矛盾。你说你需要没有类似的文章,然后继续列出一个用例,当有类似的文章时该怎么做?你能提供示例数据和期望的结果来说明你想做什么吗?@Lock:对不起,可能我不够清楚。这个案例是关于在Articles表中而不是在结果集中有相似的article行(=由SimilarArticles表连接)。在结果集中,我想排除类似的文章。@Gordon Linoff:非常感谢您的回答!我添加了一些示例,希望通过这种方式使其更清晰。感谢非常好的链接。但我认为这会过滤掉所有类似的文章,没有例外。我试图做到的是在结果集中的一组类似文章中保持文章的最高优先级。谢谢你回答Harper。我还尝试了
联合
内部联接
,但我想不出一个可行的解决方案。如果我正确理解
从文章中选择max(priority)
将在此处获取整个表的最大优先级,而不是一组类似文章的最大优先级。现在,我发现了一个在迭代结果集时跳过类似文章的部分解决方案(请参见我的答案)。运行我的完整查询对您有用吗?只需复制并粘贴整个块,其中包含所有的并集。它应该返回您想要的两行(ID2和ID3)。它不仅仅返回优先级(这只是查询的嵌套部分)。嘿,我运行查询时做了一些小的修改,因为我遇到了错误:我将WHERE部分中的
similarearticles.id
更改为
similarearticles.id
,并将
选择最大(优先级)
更改为
选择最大(优先级)
。它确实适用于样本数据。但是,如果您只是在Article表中添加一行优先级更高的内容(就像我刚才在示例数据中所做的那样),它将不再有效。我猜子查询返回的是整个表的最大值,而不是像它应该的那样只与一组类似的问题相关?
id  similar_ids    text   priority
1   3,4            FooA   3
4   3,1            FooC   2         <- Will be skipped
2   NULL           Bar    1         
3   1,4            FooB   1         <- Will be skipped