简体   繁体   English

MySQL多对多关系选择条件

[英]MySQL Many-to-Many Relationship Select Conditions

I have two tables books and tags which are in a many-to-many relationship via the table books_tags. 我有两个表书和标签,它们通过表books_tags具有多对多关系。 What I want to do is select all books that have one or more tag(s) like '%tag%'. 我想做的是选择所有带有一个或多个标签(如“%tag%”)的图书。 No problem. 没问题。 However, I also have a group_concat field which I want to be filled with all the tags that are related to the selected book. 但是,我还有一个group_concat字段,我想用与所选书本相关的所有标签来填充。

My select query basically looks like this: 我的选择查询基本上看起来像这样:

select
  flbdb_books.id,
  flbdb_books.title,
  flbdb_tags.id,
  flbdb_tags.name,
  group_concat(distinct concat('["', flbdb_tags.id, '","', flbdb_tags.name, '"]') separator ',') as tags

from
  flbdb_books

join flbdb_books_tags
  on flbdb_books.id = flbdb_books_tags.book_id
join flbdb_tags 
  on flbdb_tags.id = flbdb_books_tags.tag_id

group by flbdb_books.id;

This delivers the desired result if I don't have any conditions. 如果我没有任何条件,这将提供理想的结果。 I use PHP and json_decode to read the tags field. 我使用PHP和json_decode读取标签字段。 I have tried three different ways to filter the results, but none of them works. 我尝试了三种不同的方法来过滤结果,但是没有一种有效。

  1. use where: 在以下地方使用:

    where flbdb_tags.name like '%poetr%'

    however, this means that the tags field (the one that is assembled using group_concat) is only filled with this tag 但是,这意味着标签字段(使用group_concat组装的标签字段)仅填充了此标签

  2. use having 使用具有

    having flbdb_tags.name like '%poetr%'

    this does not return all books tagged poetry, because in some cases the poetry tag is hidden behind another tag due to the group by 这不会返回所有标记有诗歌的书籍,因为在某些情况下,由于分组依据,诗歌标签被隐藏在另一个标签的后面

  3. use having on the group_concat field 使用在group_concat字段上

    having tags like '%poetr%'

    this would actually do the trick, but I need to do the case-insensitive searching, and upper(tags) doesn't work 这实际上可以解决问题,但是我需要进行不区分大小写的搜索,并且upper(tags)不起作用

I hope it is clear what I want to do. 我希望很清楚我想做什么。

Thanks 谢谢

Will it work for you? 对您有用吗?

select
flbdb_books.id,
flbdb_books.title,
COUNT(CASE
WHEN flbdb_tags.name LIKE '%poetr%' THEN 1
END) as num_poetry,  
group_concat(distinct concat('["', flbdb_tags.id, '","', flbdb_tags.name,  
'"]')         separator ',') as tags   
from
flbdb_books

join flbdb_books_tags
on flbdb_books.id = flbdb_books_tags.book_id
join flbdb_tags 
 on flbdb_tags.id = flbdb_books_tags.tag_id

group by flbdb_books.id
HAVING num_poetry >0;

Not sure I clearly understand, but I'd try to wrap your original select and do the filtering in the wrapper select 不确定我是否清楚理解,但是我会尝试包装您的原始选择并在包装选择中进行过滤

select * from (
select
  flbdb_books.id,
  flbdb_books.title,
  flbdb_tags.id,
  flbdb_tags.name,
  group_concat(distinct concat('["', flbdb_tags.id, '","', flbdb_tags.name, '"]') separator ',') as tags
from
  flbdb_books
join flbdb_books_tags
  on flbdb_books.id = flbdb_books_tags.book_id
join flbdb_tags 
  on flbdb_tags.id = flbdb_books_tags.tag_id
group by flbdb_books.id) inner_select
where upper(inner_select.name) like '%herpderp%'

There is a relational query that does exactly what you need. 有一个关系查询可以完全满足您的需求。

The insight is that the filter tag is your starting point, and you actually need to join from the tag to the book back on to tags. 洞察力是,过滤器标签是您的起点,实际上,您需要从标签连接到书本再回到标签。

select
 books.id,
 books.title,
 tags.id,
 tags.name,

 group_concat(distinct concat('["', tags.id, '","', tags.name, '"]') separator ',') as tags

from flbdb_tags filter_tag

join flbdb_books_tags filter_book_tags 
  on filter_tag.id = filter_book_tags.tag_id

join flbdb_books books
  on filter_book_tags.book_id = books.id

join flbdb_books_tags books_tags
  on books.id = books_tags.book_id

join flbdb_tags tags
  on tags.id = books_tags.tag_id

where filter_tag.name like '%poetr%'

group by books.id;

You need to join twice, not once since the tag you filter is a different set of data then all tags for a book. 您需要加入两次,而不是一次,因为过滤的标签是书的所有标签所不同的数据集。

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

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