【问题标题】:POSTGRES aggregate data from joined tablePOSTGRES 聚合来自连接表的数据
【发布时间】:2014-07-14 21:45:03
【问题描述】:

有 sql-query,在 POSTGRES 9.1 中运行。该查询使用 24 个 LEFT JOIN。 每个连接表可以有 1 到 10-15 个数据行,与前一个表相关。由于 sql-query 我有很多数据行,彼此相差 1 个值

SQL 查询示例:

SELECT
   asw.surname,
   asw.firstname,
   asw.fathername,
   asw.birthday,
   asbe.institue_title,
   asht.honour_type
  /* Other fields are hidden to simplify example */
FROM
    /* Table of staff */ 
    agency_socworker AS asw 
LEFT JOIN
    /* Table contains staff honours */ 
    agency_socworkerhonours AS ash 
    ON asw.id = ash.socworker_id 
LEFT JOIN
    /* Table contains name of the certain honour_id */ 
    agency_socworker_honourtype AS asht 
    ON ash.honour_name_id = asht.id 
LEFT JOIN
    /* Table contains education data */ 
    agency_socworker_base_edu AS asbe 
    ON asbe.socworker_id = asw.id 
/* Other part of query is hidden to simplify example */
ORDER BY
    asw.surname ASC

结果示例:

surname---firstname---fathername---birthday-----honour_type----institue_title1
Surname---firstname---fathername---1965-01-01---TYPE1----------institue_title1
Surname---firstname---fathername---1965-01-01---TYPE2----------institue_title1
Surname---firstname---fathername---1965-01-01---TYPE3----------institue_title1
Surname---firstname---fathername---1965-01-01---TYPE4----------institue_title1
Surname---firstname---fathername---1965-01-01---TYPE5----------institue_title1

Surname---firstname---fathername---1965-01-01---TYPE1----------institue_title2
Surname---firstname---fathername---1965-01-01---TYPE2----------institue_title2
Surname---firstname---fathername---1965-01-01---TYPE3----------institue_title2
Surname---firstname---fathername---1965-01-01---TYPE4----------institue_title2
Surname---firstname---fathername---1965-01-01---TYPE5----------institue_title2

我想得到以下内容:

surname---firstname---fathername---birthday--------honour_type----------------------institue_title
Surname---firstname---fathername---1965-01-01---TYPE1, TYPE2, TYPE3, TYPE4, TYPE5---institue_title1, institue_title2

我使用array_agg函数来实现这个目标:

SELECT
    asw.surname,
    asw.firstname,
    asw.fathername,
    asw.birthday,
    array_agg( asbe.institue_title ) AS honour_type
    array_agg( asht.honour_type ) AS honour_type
    /* Other fields are hidden to simplify example */
    FROM
        /* Table of staff */ 
        agency_socworker AS asw 
    LEFT JOIN
        /* Table contains staff honours */ agency_socworkerhonours AS ash 
        ON asw.id = ash.socworker_id 
    LEFT JOIN
        /* Table contains name of the certain honour_id */ 
        agency_socworker_honourtype AS asht 
          ON ash.honour_name_id = asht.id 
    LEFT JOIN
        /* Table contains education data */ 
        agency_socworker_base_edu AS asbe 
        ON asbe.socworker_id = asw.id 
GROUP BY
    asw.surname,
    asw.firstname,
    asw.fathername,
    asw.birthday
ORDER BY
    asw.surname ASC

但这需要对不在“array_agg”函数中的字段进行“GROUP BY”语句。由于完整的 SQL 查询包含 24 个连接表,我必须使用

GROUP BY
    asw.surname,
    asw.firstname,
    asw.fathername,
    asw.birthday,
    ag.shortname,
    agr.shortname,
    agr.fullname,
    agdis.shortname,
    agdis.fullname,
    aorg.name,
    agc.name,
    agc.atype,
    asnji.id,
    asnji.new_job_contract_date,
    assp.struct_name,
    agdep.number,
    agdep_type.name,
    agdep_type.dtype,
    aswl.work_length_checkdate,
    aswl.work_length_protection_length_years,
    aswl.work_length_protection_length_days,
    aswl.work_length_protection_length_months

这会减慢查询速度。使用“分组依据”,获取前 100 个数据行需要 2 秒。如果没有“array_agg”和“group by”语句,它需要 250 毫秒,但我必须有分页。我无法进行分页,因为我不知道有多少数据行可以获得 100 个唯一行。

【问题讨论】:

    标签: postgresql query-optimization postgresql-9.1


    【解决方案1】:

    您能做的最好的事情就是预先聚合并重新加入。我不确定性能影响,但是按表达式分组的情况要少得多。对其他表使用相同的技术

    with asw_agg as (
        select
            asw.id,
            array_agg(asbe.institue_title) as institute_title,
            array_agg(asht.honour_type) as honour_type
        from
            agency_socworker asw 
            left join
            agency_socworkerhonours ash on asw.id = ash.socworker_id 
            left join
            agency_socworker_honourtype asht on ash.honour_name_id = asht.id 
            left join
            agency_socworker_base_edu asbe on asbe.socworker_id = asw.id 
        group by asw.id
    )
    select
        asw.surname,
        asw.firstname,
        asw.fathername,
        asw.birthday,
        asw_agg.honour_type,
        asw_agg.institute_title
    from
        asw
        inner join
        asw_agg using (id)
    order by asw.surname asc
    

    【讨论】:

    • 感谢一百万!我会尝试。我认为你是对的,这是最好的解决方案。我想投票给你回答,但我不能:(
    猜你喜欢
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 1970-01-01
    • 2020-01-12
    相关资源
    最近更新 更多