我在编写SELECT
查询时遇到问题,该查询包含多对多关系中的所有3个表。我有以下表格:
Table "public.companies"
Column | Type | Modifiers | Storage | Stats target | Description
----------------+------------------------+--------------------------------------------------------+----------+--------------+-------------
id | integer | not null default nextval('companies_id_seq'::regclass) | plain | |
name | character varying(48) | not null | extended | |
description | character varying(512) | | extended | |
tagline | character varying(64) | | extended | |
featured_image | integer | | plain | |
Indexes:
"companies_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "company_category_associations" CONSTRAINT "company_category_associations_company_id_foreign" FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE
Table "public.company_category_associations"
Column | Type | Modifiers
-------------+---------+----------------------------------------------------------------------------
id | integer | not null default nextval('company_category_associations_id_seq'::regclass)
company_id | integer | not null
category_id | integer | not null
Indexes:
"company_category_associations_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"company_category_associations_category_id_foreign" FOREIGN KEY (category_id) REFERENCES company_categories(id) ON DELETE RESTRICT
"company_category_associations_company_id_foreign" FOREIGN KEY (company_id) REFERENCES companies(id) ON DELETE CASCADE
Table "public.company_categories"
Column | Type | Modifiers
-------------+-----------------------+-----------------------------------------------------------------
id | integer | not null default nextval('company_categories_id_seq'::regclass)
name | character varying(32) | not null
description | character varying(96) |
Indexes:
"company_categories_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "company_category_associations" CONSTRAINT "company_category_associations_category_id_foreign" FOREIGN KEY (category_id) REFERENCES company_categories(id) ON DELETE RESTRICT
我的companies
表格大约有10万行,公司最多可以关联10个类别。当然,我一次不会选择200多家公司。
我设法通过以下查询获得结果:
select
c.id as companyid,
c.name as companyname,
cat.id as categoryid,
cat.name as categoryname
from company_categories cat
left join company_category_associations catassoc on catassoc.category_id = cat.id
left join companies c on catassoc.company_id = c.id where c.id is not null;
这个问题来自我需要以JSON格式呈现数据的事实,我希望它看起来像这样:
{
"companies": [
{
"name": "...",
"description": "...",
"categories": [
{
"id": 12,
"name": "Technology"
},
{
"id": 14,
"name": "Computers"
},
]
},
/* ... */
]
}
基本上我想尽可能少地查询这些数据。
SELECT
查询以满足我的需求?谢谢!
P.S。我正在使用PostgreSQL 9.6.6
答案 0 :(得分:1)
您可以直接从postgresql中获取json。
首先定义要输出的复合类型(json对象)。这是为了获取字段的名称,否则它们将被命名为f1,f2,...
create type cat as (id integer, name varchar);
create type comp as (id integer, name varchar, categories cat[]);
然后选择包含嵌套的猫数组作为json的comps数组
select to_json(array(
select (
c.id,
c.name,
array(
select (cc.id, cc.name)::cat
from company_categories cc
join company_category_associations cca on (cca.category_id=cc.id and cca.company_id=c.id)
))::comp
from companies c
)) as companies
答案 1 :(得分:0)
您可以嵌套两个JSON聚合到达此位置。
第一级为每个公司创建一个JSON值,并将类别存储为数组:
select to_jsonb(c) || jsonb_build_object('categories', jsonb_agg(cc)) comp_json
from companies c
join company_category_associations cca on cca.company_id = c.id
join company_categories cc on cc.id = cca.category_id
group by c.id;
每个公司返回一行。现在,我们需要将这些行聚合为一个JSON值:
select jsonb_build_object('companies', jsonb_agg(comp_json))
from (
select to_jsonb(c) || jsonb_build_object('{categories}', jsonb_agg(cc)) comp_json
from companies c
join company_category_associations cca on cca.company_id = c.id
join company_categories cc on cc.id = cca.category_id
group by c.id
) t;