【问题标题】:resolution of many to many in SQLSQL中多对多的解析
【发布时间】:2023-04-09 15:22:02
【问题描述】:

由于我仍然感到困惑,所以我重新询问了这个问题,因此我还添加了一些修改。

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

我明白这一点,但是,在向数据库中添加值时,我无法通过填充表来将三者关联在一起。例如,我将如何添加一些(例如 4)歌曲进入播放列表表,使用交集表?另外,我将如何添加哪些歌曲在哪个播放列表中的详细信息?正如我目前所看到的,我会在交集表中使用“播放列表”和“歌曲”的主键,但我不确定在哪里、如何以及为什么。

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

【问题讨论】:

  • 你是对的,insertsection 表列出了两个相关表的主键。这些列本身成为交叉表的组合(至少 2 个)主键列。此外,交集可以有数据列,但您必须始终牢记,任何数据列要么与对象 A(在您的情况下为歌曲)直接相关,要么与对象 B(播放列表)直接相关,要么与对象 A 和对象 B 之间的关系。任何数据列都直接链接到这 3 个中的一个,无一例外。这就是关系数据库的全部意义所在。

标签: sql database oracle oracle11g


【解决方案1】:

您必须区分插入歌曲和播放列表并将它们链接在一起。首先总是插入丢失的歌曲和播放列表

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`);

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

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

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

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

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


这假定以下表结构

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

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

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

PK 表示主键FK 表示外键

【讨论】:

    【解决方案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);
    

    小提琴: 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 |
    

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

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

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

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

    【讨论】:

      【解决方案3】:

      如果您的表PLAYLIST 具有主键PLAYLIST_ID,并且您的表SONG 具有主键SONG_ID,那么交集表SONGLOG(我不确定这是一个特别好的表名称,也许尝试其他类似PLAYLIST_SONG) 应该有一个由PLAYLIST_IDSONG_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 );
      

      希望这会有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-02-12
        • 2021-11-04
        • 2014-06-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多