如何从此数据库布局的 1:M 关系中删除冗余并仍然能够摘录所需的数据?

How do I remove redundancy from this database layout's 1:M relationship and still be able to excerpt the data needed?

数据库如下所示:

CREATE TABLE artists (
    artist_id       SERIAL  PRIMARY KEY,
    artist          TEXT    UNIQUE NOT NULL
);

CREATE TABLE artistalias (
    artistalias_id  SERIAL  PRIMARY KEY,
    artist_id       SERIAL  REFERENCES artists (artist_id),
    alias           TEXT    UNIQUE NOT NULL
);

CREATE TABLE songs (
    song_id         SERIAL  PRIMARY KEY,
    song            TEXT    NOT NULL,
    artist_id       SERIAL  REFERENCES artists (artist_id)
);

我的问题是数据库中包含使用两个或更多 假名的艺术家。例如,一位艺术家使用艺名 Assassin 来表示属于某一流派的歌曲,而使用名称 Agent Sasco 来表示属于另一种流派的歌曲。 有些艺人只是时不时地随便改个笔名。

稍后网站应按以下格式显示数据:

Artist      | Song
------------+-------------------
Assassin    | Anywhere We Go
Agent Sasco | We Dem A Watch

当您单击艺术家时,它会 link 您进入一个页面,该页面显示该艺术家用于表演歌曲的所有不同别名。 重要的是,歌曲以发行时所用的艺术家的笔名显示。

我使用的虚拟数据如下所示:

INSERT INTO artists (artist) VALUES
  ('Assassin'), ('Agent Sasco'), ('Sizzla');

-- This bothers me as its a lot of redundant data
INSERT INTO artistalias (artist_id, alias) VALUES
  (1, 'Agent Sasco'), (2, 'Assassin');

INSERT INTO songs (song, artist_id) VALUES 
  ('Anywhere We Go', 1), ('We Dem A Watch', 2), ('Only Takes Love', 3);

这个数据库布局困扰我的是我必须向 artistalias 添加冗余数据。必须有更好的方法将 link table artistsartistaliassongs 而不必多次添加一个特定的艺术家和他的别名?

以所需格式显示数据的查询如下所示:

SELECT
  artist AS pseudonyme_song_was_performed_with, 
  string_agg(alias, ' & ') AS other_pseudonymes,
  song
FROM
  artists
  left JOIN artistalias USING (artist_id)
  left JOIN songs USING (artist_id)
GROUP BY artist, song;

这里是 SQLFiddle 布局和数据如上所述。

您应该在 artists table 中存储艺术家的真实姓名。

然后将该艺术家的所有别名存储在 artistalias table。

然后将 artistalias_id 存储在 songs table 中。

这样,您将不会有任何重复数据。

    CREATE TABLE artists (
        artist_id       SERIAL  PRIMARY KEY,
        artist          TEXT    UNIQUE NOT NULL
    );

    CREATE TABLE artistalias (
        artistalias_id  SERIAL  PRIMARY KEY,
        artist_id       SERIAL  REFERENCES artists (artist_id),
        alias           TEXT    UNIQUE NOT NULL
    );

    CREATE TABLE songs (
        song_id         SERIAL  PRIMARY KEY,
        song            TEXT    NOT NULL,
        artistalias_id  SERIAL  REFERENCES artistalias (artistalias_id)
    );

然后这样插入数据:

    INSERT INTO artists (artist) VALUES
      ('Jeffrey Campbell'), ('Sizzla');

    -- THIS REDUNDANCY IS BOTHERING ME
    INSERT INTO artistalias (artist_id, alias) VALUES
      (1, 'Agent Sasco'), (1, 'Assassin');

    INSERT INTO songs (song, artistalias_id) VALUES 
      ('Anywhere We Go', 1), ('We Dem A Watch', 2);

并这样查询:

    SELECT
      a1.alias AS pseudonyme_song_was_performed_with, 
      string_agg(a2.alias, ' & ') AS other_pseudonymes,
      song
    FROM
      artistalias a1
      left JOIN artistalias a2 on a2.artist_id = a1.artist_id
      left JOIN songs s on s.artistalias_id = a1.artistalias_id
    GROUP BY a1.alias, song;

Fiddle: http://sqlfiddle.com/#!15/3a78c/8/0