2017-03-02 44 views
0

我有一个project表与m2m密钥到users表和skills表。Postgres加入返回加倍列时使用聚合

我想执行一个请求postgres在哪里我得到了每个项目的技能和用户列表。

因此,在本质

{ 
    "project": "foo", 
    "skills": [ 
    { 
     "id":1, 
     "name": "js" 
    }, 
    { 
     "id":2, 
     "name": "py" 
    } 
    ], 
    "members":[ 
    { 
     "id":1, 
     "name": "foo" 
    }, 
    { 
     "id":2, 
     "name": "bar" 
    } 
    ] 
} 

我使用的json_build_object到多种技能/用户行转换到一个JSON数组

这是我的SQL

SELECT project.id AS project_id, 
     project.name AS project_name, 
     array_agg(json_build_object('skill_id',s.id,'name',s.skill)) AS skills, 
     array_agg(json_build_object('id',p.project,'name',p.Username)) AS members 

from project 

    LEFT JOIN (
     select project_skills.id,project_skills.skill,project_skills.project AS name 
     from project_skills 
    ) s on s.name = project.name 

LEFT JOIN (
    select account_projects.Username, account_projects.project AS name 
    from account_projects 
) p on p.name = project.name 

WHERE project.id = $1 
GROUP BY project_id,project_name 

如果我运行这个查询虽然,技能/用户表是加倍(而不是3个用户,我得到6)。

我应该添加到查询中以确保没有重复计数?

我使用的Postgres 9.4

回答

1

你沿着两个不同的维度聚集。你应该聚集前加入,而不是后:

select p.id as project_id, p.name as project_name, 
     s.skills, ap.members 
from project p left join 
    (select s.id, s.name, 
      array_agg(json_build_object('skill_id', s.id, 'name', s.skill)) as skills 
     from project_skills s 
     group by s.name 
    ) s 
    on s.name = p.name left join 
    (select ap.name, 
      array_agg(json_build_object('id', ap.project, 'name', ap.Username)) as members 
     from account_projects ap 
     group by ap.name 
    ) ap 
    on ap.name = p.name 
where p.id = $1; 

编辑:

因为你只选择一个项目,它可能是更便宜地使用横向联接或相关子查询:

select p.id as project_id, p.name as project_name, 
     (select s.id, s.name, 
       array_agg(json_build_object('skill_id', s.id, 'name', s.skill)) as skills 
     from project_skills s 
     where s.name = p.name 
     ) skills, 
     (select ap.name, 
      array_agg(json_build_object('id', ap.project, 'name', ap.Username)) as members 
     from account_projects ap 
     where ap.name = p.name 
     ) as members 
from project p 
where p.id = $1; 
+0

谢谢你展示第二个:) – Kannaj

0

如果您可以使用jsonb代替json,则查询可能如下所示:

SELECT project.id AS project_id, 
     project.name AS project_name, 
     jsonb_agg(DISTINCT jsonb_build_object('skill_id',s.id,'name',s.skill)) AS skills, 
     jsonb_agg(DISTINCT jsonb_build_object('id',p.id,'name',p.Username)) AS members 

from project 

    LEFT JOIN (
     select project_skills.id,project_skills.skill,project_skills.project AS name 
     from project_skills 
    ) s on s.name = project.name 

LEFT JOIN (
    select account_projects.id, account_projects.Username, account_projects.project AS name 
    from account_projects 
) p on p.name = project.name 

WHERE project.id = 1 
GROUP BY project_id,project_name 

至少是更好地使用jsonb_agg而不是array_agg。