Php 如何使用MySQL左键连接两个表并从子查询的主查询中排除多行?

Php 如何使用MySQL左键连接两个表并从子查询的主查询中排除多行?,php,mysql,subquery,Php,Mysql,Subquery,我不熟悉php和MySQL,并通过编写自定义CMS开始探索这两种技术 我有一个名为news的表,其中包含许多新闻条目,这些条目由主键news_id自动递增: 新闻id、标题、副标题 我有另一个名为news_tags的表,其中包含由主键news_tag_id自动递增的标记标题: 新闻标签新闻标签id,新闻标签标题 因为每个新闻条目都可以用多个标记标题进行标记,并且每个标记标题可以描述多个新闻条目,所以两个表都是多对多关系。因此,如果一个新闻条目被标记,我将它们的关系存储在第三个名为news_tag

我不熟悉php和MySQL,并通过编写自定义CMS开始探索这两种技术

我有一个名为news的表,其中包含许多新闻条目,这些条目由主键news_id自动递增:

新闻id、标题、副标题

我有另一个名为news_tags的表,其中包含由主键news_tag_id自动递增的标记标题:

新闻标签新闻标签id,新闻标签标题

因为每个新闻条目都可以用多个标记标题进行标记,并且每个标记标题可以描述多个新闻条目,所以两个表都是多对多关系。因此,如果一个新闻条目被标记,我将它们的关系存储在第三个名为news_tags_relations的表中,该表包含具有news_id和news_tag_id的行:

新闻标签关系新闻id,新闻标签id

现在,我想让用户可以选择标签,以便为可能已经有标签或可能没有标签的新闻条目添加标签

因此,我需要选择所有标签标题及其标题id,它们根本不链接到任何新闻条目,还需要选择所有标签标题,它们链接到其他新闻条目,但尚未为用户正在处理的新闻条目选择

如果新闻条目的news_id仅链接到一个标记,则此操作非常有效:

SELECT news_tags.news_tag_title, news_tags_relations.news_id, news_tags.news_tag_id
FROM news_tags
LEFT JOIN news_tags_relations ON news_tags.news_tag_id = news_tags_relations.news_tag_id
WHERE news_tag_title != (

SELECT news_tag_title
FROM news_tags_relations
JOIN news_tags ON news_tags_relations.news_tag_id = news_tags.news_tag_id
WHERE news_tags_relations.news_id = '".$news_id."'
)
但是如果选择的新闻id链接到两个或更多标签,我会得到:

1242-子查询返回超过1行 这对我来说很有意义,因为链接到该新闻id的标签数量大于1,而且MySQL似乎无法处理返回多行的子查询

如果拾取的新闻id未链接到任何标记,我将得到空结果。我试着用替换来解决这个问题

WHERE news_tag_title != (

这并没有改变结果为0

这是我能得到的最接近的


如何修改查询以使其适用于链接到多个标记或根本没有标记的条目?

您可以重写查询,而无需使用子查询,也可以在ON子句中添加另一个条件


上面的查询将连接行news\u tags\u relations,其中news\u tags\id等于news\u tags\u relations中的news\u tag\id,而news\u tags\u relations中的news\u id不等于当前的news id,即您要分配标签的新闻id,因此使用左连接,因此所有行都将根据ON nt返回。news\u tag\u id=ntr.news_标记_id和ntr.news_id!='$news_id.“条件。注意,我没有在整个结果集中使用WHERE过滤器,我在on子句中使用了另一个条件,因此所有标记都将返回,但已分配的标记除外。我最终解决了它。多亏了@plantheidea,子查询可以从左连接的结果集中删除包含已分配给其他新闻ID的新闻标签标题的所有行。排除这些行的条件是子查询未检测到的新闻标签标题。未分配给任何新闻标签标题的新闻条目出现在结果集中,因为它们的新闻id为NULL,并且由新闻标签标题为NULL的位置包含。 最后,我必须按新闻标签标题添加分组,以避免在当前“$news\u id.”未分配给任何新闻标签标题时出现重复的新闻标签标题结果

因此,工作查询是:

选择news\u tags.news\u tag\u title、news\u tags\u relations.news\u id、news\u tags.news\u tag\u id 从新闻标签 LEFT JOIN news\u tags\u relations ON news\u tags.news\u tag\u id=news\u tags\u relations.news\u tag\u id 其中news_tag_title为NULL或news_tag_title不在 选择新闻\标签\标题 来自新闻标签关系 在news\u tags\u relations.news\u tag\u id=news\u tags.news\u tag\u id上加入news\u标签 其中news\u标记了\u relations.news\u id='.$news\u id'
按新闻标签标题分组,而不是!=,使用NOT IN将解决子查询中的多结果问题。Thx,非常接近。现在适用于未分配给任何新闻id的标记。我在子查询中尝试的是通过排除标题检测到的行来删除所有包含已分配给当前新闻id的相同标记标题的行。您的查询将通过标记与当前新闻id的关系来检测包含该标记的每一行,但如果将其他新闻id分配给该标记,则标记标题在结果集中保留的次数与其他新闻id分配给该标题的次数相同。例如,处理新闻id 1:如果新闻id 1被分配给标签id 1,新闻id 5也被分配给标签id 1,则标题仍然出现在新闻id 5上
WHERE news_tag_title IS NULL OR news_tag_title != (
SELECT DISTINCT
nt.news_tag_title,
nt.news_tag_id
FROM 
news_tags nt
LEFT JOIN news_tags_relations ntr
ON nt.news_tag_id = ntr.news_tag_id
AND ntr.news_id !='".$news_id."'