如何最有效地查询 SQL 数据库中的多对多关系

问题描述 投票:0回答:1

假设我有一个歌曲数据库。每首歌可能有多个作曲家,每个作曲家可能有不止一首歌曲:这是一种简单的多对多关系,我在 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

目前来说,这已经完成了工作,但即使作为初学者,对列表中的每个项目运行数据库查询也感觉非常错误。所以我想我的问题是双重的:

  1. 是否可以构建一个单一的 SQL 查询来让我一次检索所有信息?感觉应该是这样,但我不太明白。

  2. 鉴于它可能出现在我的应用程序中的任何位置,一首歌曲将始终显示在带有作曲家的卡片中,我是否应该考虑将作曲家数据复制到歌曲表的附加列中?基本上就是做这样的事情。

songs:  
id | title                   | composers                   | ...
-----------------------------------------------------------| ...
0  | 'We are the champions'  | 'Brian May, Freddie Mercury'| ...
1  | 'Piano man'             | 'Billy Joel'                | ...
2  | 'Happy birthday'        | null                        | ...

从性能(和简单性)的角度来看,避免在我的应用程序的每个视图上的作曲家表上加入 JOIN 似乎非常有吸引力,但是值得额外的数据库复杂性吗?

sql flutter sqlite many-to-many
1个回答
0
投票

您可以使用 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
© www.soinside.com 2019 - 2024. All rights reserved.