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 更宽,包含用户在查询中经常查找的信息。同样,当 运行 执行某些查询时,分区也可以产生显着的性能提升。
我再次提出这个问题,因为我仍然很困惑,所以我也添加了一些编辑。
对于多对多关系,交集 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 更宽,包含用户在查询中经常查找的信息。同样,当 运行 执行某些查询时,分区也可以产生显着的性能提升。