我有一个project
表,其中m2m键是users
表和skills
表。
我正在尝试向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
答案 0 :(得分: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;
答案 1 :(得分: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。