SQL 中多对多的分辨率

resolution of many to many in SQL

我再次提出这个问题,因为我仍然很困惑,所以我也添加了一些编辑。

对于多对多关系,交集 table 用于将其解析为两个一对多关系。我的问题是我目前有 2 个 table、"Playlist" 和 "song"。每首歌曲出现在多个播放列表中,每个播放列表可以包含多首歌曲。要解决此问题,请添加第三个 table、"songlog" 以解决多对多问题。

我明白这一点,但是,当涉及到向数据库中添加值时,我无法集中精力填充 table 以将三者联系在一起。例如,如何将我使用交集 table 将一些(例如 4 首)歌曲添加到播放列表 table 中?另外,我将如何添加哪些歌曲在哪个播放列表中的详细信息?正如我目前看到的那样,我会在交叉点 table 中同时使用 "Playlist" 和 "song" 的主键,但我不确定在哪里、如何以及为什么。

我仍然很困惑,所以对这个设计领域进行清晰和基本的解释可能会有所帮助!非常感谢。

您必须区分插入歌曲和播放列表和 link将它们放在一起。首先始终插入丢失的歌曲和播放列表

INSERT INTO song (SongID, Name) VALUES (7, 'New song 1');
INSERT INTO song (SongID, Name) VALUES (8, 'New song 2');

INSERT INTO playlist (PlaylistID, Name) VALUES (15, 'The new playlist`);

完成歌曲和播放列表后,您可以link将它们放在一起:

INSERT INTO songlog (SongID, PlaylistID) VALUES (7, 15);
INSERT INTO songlog (SongID, PlaylistID) VALUES (8, 15);

这会将歌曲 7 和歌曲 8 添加到播放列表 15。您也可以将一首歌曲添加到另一个播放列表(假设播放列表 table 中已经有播放列表 #33):

INSERT INTO songlog (SongID, PlaylistID) VALUES (7, 33);

您不必再次将歌曲插入歌曲 table。每首歌曲和每个播放列表恰好退出一次。


这假定以下 table 结构

Table song
----------
PK SongID
   Name

Table playlist
--------------
PK PlaylistID
   Name

Table songlog
-------------
PK FK SongID
PK FK PlaylistID

PK表示主键FK表示外键.

如果你的tablePLAYLIST有主键PLAYLIST_ID,而你的tableSONG有主键SONG_ID,那么交集table SONGLOG(我不确定 table 的名字是否特别好,也许可以尝试其他类似 PLAYLIST_SONG 的名字)应该有一个由 [=14 组成的主键=] 和 SONG_ID。它可以有一个额外的列,比如 SONG_ORDER,这样就可以为播放列表排序歌曲。

假设您有以下播放列表:

PLAYLIST_ID  PLAYLIST_NAME
1            David's Songs

以及以下歌曲:

SONG_ID  SONG_NAME
1        Big Country
2        She Hangs Brightly

那么您可以将这些歌曲添加到 SONGLOG,如下所示:

INSERT INTO songlog ( playlist_id, song_id, song_order )
VALUES ( 1, 1, 1 );

INSERT INTO songlog ( playlist_id, song_id, song_order )
VALUES ( 1, 2, 2 );

希望对您有所帮助。

以下是您的 DDL(数据定义语言)的样子,带有一些示例插入:

create table playlist
(
  playlist_id numeric(10) not null,
  playlist_name varchar(25),
     constraint p_id_pk primary key (playlist_id)
);

create table songs
(
  song_id numeric(10) not null,
  song_name varchar(25),
     constraint s_id_pk primary key (song_id)
);

create table playlist_songs
(
  playlist_id,
  song_id,
  song_order int,
     constraint p_fk foreign key (playlist_id) references playlist(playlist_id),
     constraint s_fk foreign key (song_id) references songs(song_id)
);

insert into playlist values (1, 'A cool playlist');
insert into playlist values (2, 'An okay playlist');

insert into songs values (1, 'ABC');
insert into songs values (2, 'DEF');
insert into songs values (3, 'GHI');
insert into songs values (4, 'JKL');

insert into playlist_songs values (1, 1, 1);
insert into playlist_songs values (1, 3, 2);

insert into playlist_songs values (2, 2, 1);
insert into playlist_songs values (2, 3, 2);

Fiddle: http://sqlfiddle.com/#!4/0420f/5/0

还有一个 SELECT 查询的示例,您可能 运行:

select ps.playlist_id,
       p.playlist_name,
       s.song_id,
       s.song_name,
       ps.song_order
  from playlist_songs ps
  join songs s
    on ps.song_id = s.song_id
  join playlist p
    on ps.playlist_id = p.playlist_id
 order by ps.playlist_id, ps.song_order

输出:

| PLAYLIST_ID |    PLAYLIST_NAME | SONG_ID | SONG_NAME | SONG_ORDER |
|-------------|------------------|---------|-----------|------------|
|           1 |  A cool playlist |       1 |       ABC |          1 |
|           1 |  A cool playlist |       3 |       GHI |          2 |
|           2 | An okay playlist |       2 |       DEF |          1 |
|           2 | An okay playlist |       3 |       GHI |          2 |

中介table的目的是数据规范化。它减少了您存储的数据量并允许更好地控制数据。

在系统中,您有一个歌库。用户可以创建播放列表并将歌曲分配给这些播放列表。您有歌曲、播放列表和歌曲到播放列表的分配。

该信息可以以非规范化的方式组合(例如在上面的查询结果中),但非规范化数据主要用于报告。当您存储数据时,您不希望将相同的数据存储在多个位置。您不应该看到存储在两个地方的播放列表的名称。或者存储在两个地方的歌曲名称。您将存储冗余数据。此外,当某些事情发生变化时,比如歌曲的大小(当前不包含在您的模式中,但可能包含),显然能够仅更新歌曲的一行 table 是理想的,而不是可能任何类型的非规范化 table.

上的数千行

非规范化 tables 确实在报告环境中占有一席之地,因为它们在选择数据进行报告和分析时涉及较少的 table 连接。 table 更宽,包含用户在查询中经常查找的信息。同样,当 运行 执行某些查询时,分区也可以产生显着的性能提升。