假设我有一个歌曲数据库。每首歌可能有多个作曲家,每个作曲家可能有不止一首歌曲:这是一种简单的多对多关系,我在 Sqlite 中建模如下:
CREATE TABLE songs(
id INTEGER PRIMARY KEY,
title TEXT,
otherStuff...
)
CREATE TABLE composers(
id INTEGER PRIMARY KEY,
name TEXT
)
CREATE TABLE songComposers(
songId INTEGER,
composerId INTEGER,
FOREIGN KEY (scoreId) REFERENCES songs(id)
FOREIGN KEY (composerId) REFERENCES composer(id)
)
假设我的数据库如下所示。
songs:
id | title | ...
-----------------------------------
0 | 'We are the champions' | ...
1 | 'Piano man' | ...
2 | 'Happy birthday' | ...
composers:
id | name
-----------------------
0 | 'Freddie Mercury'
1 | 'Brian May'
2 | 'Billy Joel'
songComposer:
songId | composerID
--------------------
0 | 0
0 | 1
1 | 2
我的应用程序的主视图是所有歌曲的列表,其中列表的每个元素都是一张包含歌曲标题和作曲家(如果有)的卡片。基本上,这个:
我们是冠军
布莱恩·梅、弗雷迪·摩克瑞
钢琴人
比利·乔尔
生日快乐
没有作曲家
我的第一个天真的方法是先查询歌曲表
SELECT id, title FROM songs
然后,在构建每个单独的 UI 列表元素时,通过运行类似
的查询来检索任何给定
specificSongId
的作曲家
SELECT id, name FROM composers
INNER JOIN songComposer
ON composers.id = songComposer.composerId AND songComposer.songId = specificSongId
目前来说,这已经完成了工作,但即使作为初学者,对列表中的每个项目运行数据库查询也感觉非常错误。所以我想我的问题是双重的:
是否可以构建一个单一的 SQL 查询来让我一次检索所有信息?感觉应该是这样,但我不太明白。
鉴于它可能出现在我的应用程序中的任何位置,一首歌曲将始终显示在带有作曲家的卡片中,我是否应该考虑将作曲家数据复制到歌曲表的附加列中?基本上就是做这样的事情。
songs:
id | title | composers | ...
-----------------------------------------------------------| ...
0 | 'We are the champions' | 'Brian May, Freddie Mercury'| ...
1 | 'Piano man' | 'Billy Joel' | ...
2 | 'Happy birthday' | null | ...
从性能(和简单性)的角度来看,避免在我的应用程序的每个视图上的作曲家表上加入 JOIN 似乎非常有吸引力,但是值得额外的数据库复杂性吗?
您可以使用 SQL GROUP_CONCAT 生成类似 json 的作曲家列表,然后 json 在 dart 中解析它以在 UI 中显示
SELECT
songs.id AS song_id,
songs.title AS song_title,
'[' || GROUP_CONCAT(
'{' ||
'"id": ' || composers.id || ', ' ||
'"name": "' || composers.name || '"'
|| '}', ', '
) || ']' AS song_composers
FROM
songs
LEFT JOIN
songComposer ON songs.id = songComposer.songId
LEFT JOIN
composers ON songComposer.composerId = composers.id
GROUP BY
songs.id;
如果您只想要作曲家名称,那么您可以仅连接名称
GROUP_CONCAT(composers.name, ', ') AS song_composers