在一个查询中选择多个项目,这些项目本身包含许多项目?

时间:2015-06-03 00:36:00

标签: mysql sql database postgresql sqlite

我有一个代表书籍收藏的数据库。它看起来像这样:

书籍表

id    |    title            |    year    |    author_id
--------------------------------------------------------
1       How to Read              1985            7
2       A Dream of Spring        2041            14
3       Tour Guide               2010            40

标签表

id    |    tagname
-------------------
1        nonfiction
2        fiction
3        poetry
4        sci-fi
5        magical realism
6        detective

books_tags_links表

book    |    tag
------------------
8            4
10           1
10           4
10           5
8            2

书籍和标签之间存在一对多的关系:一本书可以有多个标签,如“小说,侦探,科幻”。

我想知道的是:我是否可以在一个查询中选择所有书籍与每本书相关的所有标签?我不知道结果会是什么样的 - 我想,这是一个锯齿状的数组,每本书都有不同数量的标签?

我的最终目标是输出一个HTML表格,其中每一行都是一本书,tr元素的每个标签都有一个data-tag属性,因此我可以使用JavaScript隐藏或显示带有某些标签组合的书籍。到目前为止,我只能想象如何通过为列表中的每本书发出单独的select tags查询来做到这一点,但这可能意味着要生成数千个数据库请求,我想知道是否有更聪明的方法来执行此操作

我目前正在使用SQLite,但如果有Postgres或MySQL独有的解决方案,我仍然有兴趣了解它。

2 个答案:

答案 0 :(得分:3)

在MySQL中,group_concat()可能会做你想要的:

select b.*,
       group_concat(t.tagname)
from books b join
     book_tags bt
     on b.id = bt.book join
     tags t
     on bt.tag = t.id
group by b.id;

这会将标记放在以逗号分隔的列表中,这可能是一个很好的格式。您可以使用SEPARATOR关键字更改分隔符。

答案 1 :(得分:2)

在Postgres中,您应该使用array_agg()功能来汇总链接到图书的标签。

select title, array_agg(tagname)
from books b
join books_tags_links l on l.book = b.id
join tags t on l.tag = t.id
group by 1

SQLite3中你有一个类似的函数group_concat()array_agg()返回一个数组group_concat() - 一个字符串)。