简体   繁体   English

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

[英]How to do LEFT JOIN two tables and exclude multiple rows from main query in subquery using MySQL?

I'm new to php and MySQL and started exploring both by programming a custom CMS. 我是php和MySQL的新手,并开始通过对自定义CMS进行编程来进行探索。

I have a table called news containing lots of news entries which are auto incremented by a primary key news_id: 我有一个称为新闻的表,其中包含许多新闻条目,这些条目由主键news_id自动递增:

news (news_id, title, subtitle, ...) 新闻(news_id,标题,字幕等)

I have another table called news_tags containing tag titles which are auto incremented by a primary key news_tag_id: 我还有一个名为news_tags的表,其中包含由主键news_tag_id自动递增的标签标题:

news_tags (news_tag_id, news_tag_title) news_tags(news_tag_id,news_tag_title)

Because each news entry can be tagged with multiple tag titles and each tag title can describe multiple news entries both tables are many-to-many-relation. 因为每个新闻条目都可以标记有多个标签标题,并且每个标签标题都可以描述多个新闻条目,所以两个表都是多对多关系。 So if a news entry gets tagged I store their relations in a third table called news_tags_relations holding rows with news_id and news_tag_id: 因此,如果新闻条目被标记了,我会将它们的关系存储在名为news_tags_relations的第三个表中,该表包含具有news_id和news_tag_id的行:

news_tags_relations (news_id, news_tag_id) news_tags_relations(news_id,news_tag_id)

Now I want to give the user the possibility to choose tags in order to tag a news entry which may or may not have tags already. 现在,我想为用户提供选择标签的可能性,以便为新闻条目添加标签,该新闻条目可能已经或可能没有标签。

So I need to SELECT all tag titles and their title id that are not linked to any news entry at all and also all tag titles that are linked to other news entries but were not already chosen for the news entry the user is working on. 因此,我需要选择所有根本未链接到任何新闻条目的所有标签标题及其标题ID,以及所有已链接到其他新闻条目但尚未为用户正在处理的新闻条目选择的所有标签标题。

This works perfectly fine if the news entry's news_id is linked to one tag only: 如果新闻条目的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."'
)

But if the picked news_id is linked to two or more tags I get: 但是,如果选择的news_id与两个或多个标签链接,则会得到:

1242 - Subquery returns more than 1 row 1242-子查询返回多于1行

This makes sense to me because number of tags linked to that news_id is > than 1 and it seems like MySQL can't handle subqueries returning multiple rows. 这对我来说很有意义,因为链接到该news_id的标签数量大于1,并且MySQL似乎无法处理返回多行的子查询。

If the picked news_id is not linked to any tag I get empty result. 如果选择的news_id未链接到任何标签,则结果为空。 I tried to fix that with replacing 我试图通过替换来解决

WHERE news_tag_title != (

with

WHERE news_tag_title IS NULL OR news_tag_title != (

which didn't change the result being 0. 并没有将结果更改为0。

This was closest I could get yet. 这是我能得到的最接近的。

How can I modify my Query to make it work for entries that are linked to multiple tags or no tags at all? 如何修改查询以使其适用于链接到多个标签或根本没有标签的条目?

You can rewrite your query without using a subquery as well just add another condition in your ON() clause 您可以重写查询而不使用子查询,也可以在ON()子句中添加另一个条件

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."'

Above query will join rows news_tags_relations where news_tag_id from news_tags is equal to news_tag_id from news_tags_relations and the news_id from news_tags_relations is not equal to your current news id the one you are going to assign tags and hence your using left join so all rows will be returned according to ON nt.news_tag_id = ntr.news_tag_id AND ntr.news_id !='".$news_id."' criteria.Note i have not used the WHERE filter it applies on the whole result set ,i have used one more condition in ON() clause so all the tags will return except the ones who were already assigned 上面的查询将加入行news_tags_relations其中news_tag_idnews_tags等于news_tag_idnews_tags_relationsnews_idnews_tags_relations不等于当前的新闻ID你要分配标签,因此你用左连接,因此所有的行会根据返回的一个到ON nt.news_tag_id = ntr.news_tag_id AND ntr.news_id !='".$news_id."'标准。注意,我尚未在整个结果集上使用WHERE过滤器,我在ON()子句,因此除已分配的标签外,所有标签都将返回

I finally solved it. 我终于解决了。 Thanks to @PlantTheIdea the subquery works which removes all rows from the result set of the LEFT JOIN that contain news_tag_titles already assigned to other news_ids . 由于@PlantTheIdea子查询的作品,其去除结果集中LEFT的所有行JOIN包含news_tag_titles已经分配给其他news_ids Criteria for "excluding" these rows is the news_tag_title by news_tag_title NOT IN detected by the subquery. 对于“排除”这些行的标准是news_tag_title通过news_tag_title NOT IN子查询检测。 News entries that were not assigned to any news_tag_title occur in the result set because their news_id is NULL and inculded by WHERE news_tag_title IS NULL . 未分配给任何news_tag_title新闻条目会在结果集中出现,因为它们的news_idNULL并由WHERE news_tag_title IS NULL Finally I had to add GROUP BY news_tag_title in order to avoid duplicate results of news_tag_titles that occur when current '".$news_id."' is not assigned to any news_tag_titles 最后,我必须添加GROUP BY news_tag_title ,以避免在当前'".$news_id."'未分配给任何news_tag_titles时出现重复的news_tag_titles结果'".$news_id."'

So the working query is: 因此,有效的查询是:

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 IS NULL OR news_tag_title NOT IN ( 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."' ) GROUP BY news_tag_title

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM