如何在没有 "duplicating" 聚合数据的情况下使用两个聚合函数连接多个表?

How to join multiple tables using two aggregate functions without "duplicating" aggregated data?

我正在尝试每行显示一首 tune(歌曲)以及与该特定曲调 tune_id 相关的所有数据,如果与 [=17= 相关的字段有更多条目] 我希望通过 ' & ' 聚合和连接数据。但是,我不明白为什么 string_agg(artist, ' & ')tune_id 的每个 producer 条目复制艺术家的名字。此外,string_agg(producer, ' & ') 函数也不会显示所需的结果。我假设我错误地使用了 GROUP BY 或两个聚合函数。

我目前是运行 PostgreSQL 9.1.16,虽然它会在几天内升级到最新版本。

这是一个 SQLFiddle 的所有设置,如下所述。

数据库结构为:

CREATE TABLE tunes (
    tune_id               SERIAL    PRIMARY KEY,
    tune                  TEXT      NOT NULL
);

CREATE TABLE artistnames (
    artistname_id         SERIAL    PRIMARY KEY,
    artist                TEXT      UNIQUE NOT NULL
);

CREATE TABLE artists (
   artist_id              SERIAL    PRIMARY KEY,
   artistname_id          SERIAL    REFERENCES artistnames (artistname_id),
   tune_id                SERIAL    REFERENCES tunes (tune_id)
);

CREATE TABLE producernames (
    producername_id       SERIAL      PRIMARY KEY,
    producer              TEXT        UNIQUE NOT NULL
);

CREATE TABLE producers (
    producer_id           SERIAL      PRIMARY KEY,
    producername_id       SERIAL      REFERENCES producernames (producername_id),
    tune_id               SERIAL      REFERENCES tunes (tune_id)
);

用于测试数据库的虚拟数据是:

TRUNCATE TABLE tunes, artistnames, artists, producernames, producers CASCADE;

ALTER SEQUENCE tunes_tune_id_seq RESTART WITH 1;
ALTER SEQUENCE artistnames_artistname_id_seq RESTART WITH 1;
ALTER SEQUENCE artists_artist_id_seq RESTART WITH 1;
ALTER SEQUENCE producernames_producername_id_seq RESTART WITH 1;
ALTER SEQUENCE producers_producer_id_seq RESTART WITH 1;

INSERT INTO tunes (tune)
  VALUES ('Only Takes Love'), ('Some Boy');

INSERT INTO artistnames (artist) 
  VALUES ('Sizzla'), ('Tanto Metro'), ('Devonte');

INSERT INTO artists (artistname_id, tune_id)
  VALUES (1, 1), (2, 2), (3, 2);

INSERT INTO producernames (producer)
  VALUES ('Brad "Riprock" Daymond'), ('Alexander Greggs'), ('Dennis');

INSERT INTO producers (producername_id, tune_id)
  VALUES (1, 1), (2, 1), (3, 1), (1, 2), (3, 2);

我正在使用的查询如下所示:

SELECT
    string_agg(artist, ' & ') AS artist,
    tune,
    string_agg(producer, ' & ') AS producer
FROM tunes
    FULL JOIN artists USING (tune_id)
    FULL JOIN artistnames USING (artistname_id)
    FULL JOIN producers USING (tune_id)
    FULL JOIN producernames USING (producername_id)
GROUP BY tune;

此查询返回的结果如下所示:

+-----------------------------------------------+-----------------+-------------------------------------------------------------------+
| artist                                        | tune            | producer                                                          |
+-----------------------------------------------+-----------------+-------------------------------------------------------------------+
| Sizzla & Sizzla & Sizzla                      | Only Takes Love | Brad "Riprock" Daymond & Alexander Greggs & Dennis                |
+-----------------------------------------------+-----------------+-------------------------------------------------------------------+
| Tanto Metro & Tanto Metro & Devonte & Devonte | Some Boy        | Brad "Riprock" Daymond & Dennis & Brad "Riprock" Daymond & Dennis |
+-----------------------------------------------+-----------------+-------------------------------------------------------------------+

这是我试图获得的结果:

+-----------------------+-----------------+----------------------------------------------------+
| artist                | tune            | producer                                           |
+-----------------------+-----------------+----------------------------------------------------+
| Sizzla                | Only Takes Love | Brad "Riprock" Daymond & Alexander Greggs & Dennis |
+-----------------------+-----------------+----------------------------------------------------+
| Tanto Metro & Devonte | Some Boy        | Brad "Riprock" Daymond & Dennis                    |
+-----------------------+-----------------+----------------------------------------------------+

编辑: 我不太确定 title/question 是否适合所描述的问题,如果有人有更好的 title/question 建议适合我的问题,让我知道。

SQL Fiddle

SELECT
    string_agg(distinct(artist), ' & ') AS artist,
    tune,
    string_agg(distinct(producer), ' & ') AS producer
FROM 
    tunes
    left join (
        artists 
        left JOIN 
        artistnames USING (artistname_id)
    ) a USING (tune_id)
    left JOIN (
        producers
        left JOIN 
        producernames USING (producername_id)
    ) b USING (tune_id)
GROUP BY tune;