【问题标题】:How to join multiple tables using two aggregate functions without "duplicating" aggregated data?如何使用两个聚合函数连接多个表而不“复制”聚合数据?
【发布时间】:2015-09-04 15:08:59
【问题描述】:

我正在尝试每行显示一个 tune(歌曲)以及与该特定曲调的 tune_id 相关的所有数据,如果与 tune_id 相关的字段有更多条目,我希望将数据聚合并连接起来通过' & '。但是,我不明白为什么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                    |
+-----------------------+-----------------+----------------------------------------------------+

编辑:我不太确定标题/问题是否符合所描述的问题,如果有人有更好的标题/问题建议适合我的问题,请告诉我。

【问题讨论】:

    标签: sql postgresql join group-by aggregate-functions


    【解决方案1】:

    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;
    

    【讨论】:

    • 非常感谢先生,我试过SELECT DISTINCT string_agg(... ,当然失败了,我不知道可以在聚合函数中使用它!
    猜你喜欢
    • 2013-02-22
    • 1970-01-01
    • 2014-01-21
    • 1970-01-01
    • 1970-01-01
    • 2014-09-07
    • 1970-01-01
    • 1970-01-01
    • 2020-06-19
    相关资源
    最近更新 更多