通过 searching/comparing 在数组数组中返回聚合数组
Returning an agregated array by searching/comparing in an array of arrays
我有 2 个表:
类别
id | name | | slug | path | parent_id | depth
1 name1 slug1 {1} null 0
2 name2 slug2 {1,2} 1 1
3 name3 slug3 {1,2,3} 2 2
5 nam5 slug5 {5} null 0
......
9 nam4 slug9 {5,9} 5 1
其中路径是一个 int[]array
类型并且像面包屑一样工作
项
id | name
1 name1
Item 和 Category 之间存在 M2M 关系
item_categories
id | item_id | category_id
1 1 | 3
2 1 9
在上面的示例中,项目分为 3 个类别:
我使用以下 SQL:
SELECT c1.id, c1.name, c1.slug, c1.parent_id FROM categories AS c1
WHERE ARRAY[c1.id] <@ (SELECT c2.path FROM categories AS c2 WHERE c2.id=
(SELECT category_id FROM item_categories WHERE item_id=8 LIMIT 1)) order by depth
基于路径提取面包屑并且有效。
但我想获取所有面包屑(不只是一个)。删除 LIMIT 1
并更改 = to in
我将得到一个数组数组,而不仅仅是一个数组,并且会触发错误:
more than one row returned by a subquery used as an expression
这是正常的。
我想要的示例 - 项目在:
cat1 - > cat2 - >cat3
ca5 -> cat9
,以及来自数据库(这样我就可以遍历它们):
[ [{'name':cat1, 'slug':slug1}, {'name':cat2, 'slug':slug2}, {'name':cat3, 'slug':slug3}], [{'name':cat5, 'slug':slug5}, {'name':cat9, 'slug':slug9}]]
dbfiddle: https://dbfiddle.uk/?rdbms=postgres_10&fiddle=f756cfe568d38425dfe25cfec60b1b3f
因此,除了获得一个面包屑,我如何才能获得一个面包屑数组作为结果?
使用 json_build_object
, unnest
and ordered json_agg
:
select
c.id,
json_agg(
json_build_object('name',c2.name,'slug',c2.slug)
order by p.depth
)
from categories as c
inner join lateral unnest(c.path) with ordinality as p(id, depth) on true
inner join categories as c2 on
c2.id = p.id
where
exists (
select *
from item_categories as tt
where
tt.item_id = 1 and
tt.category_id = c.id
)
group by
c.id
或者如果需要,您可以使用 table 中的 depth
列:
select
c.id,
json_agg(
json_build_object('name',c2.name,'slug',c2.slug)
order by c2.depth
)
from categories as c
inner join categories as c2 on
c2.id = any(c.path)
where
exists (
select *
from item_categories as tt
where
tt.item_id = 1 and
tt.category_id = c.id
)
group by
c.id
我不喜欢 json_build_object
is that you have to name your columns explicitly doing double work, so I've tried to useto_json
instead. It works, but honestly, I'm not that familiar with this syntax when alias of the table is passed to the function as an argument (see Using Composite Types in Queries
) and could not make it work without lateral
加入:
select
c.id,
json_agg(to_json(d) order by c2.depth)
from categories as c
inner join categories as c2 on
c2.id = any(c.path)
cross join lateral (select c.name, c.slug) as d
where
exists (
select *
from item_categories as tt
where
tt.item_id = 1 and
tt.category_id = c.id
)
group by
c.id
我有 2 个表:
类别
id | name | | slug | path | parent_id | depth
1 name1 slug1 {1} null 0
2 name2 slug2 {1,2} 1 1
3 name3 slug3 {1,2,3} 2 2
5 nam5 slug5 {5} null 0
......
9 nam4 slug9 {5,9} 5 1
其中路径是一个 int[]array
类型并且像面包屑一样工作
项
id | name
1 name1
Item 和 Category 之间存在 M2M 关系
item_categories
id | item_id | category_id
1 1 | 3
2 1 9
在上面的示例中,项目分为 3 个类别:
我使用以下 SQL:
SELECT c1.id, c1.name, c1.slug, c1.parent_id FROM categories AS c1
WHERE ARRAY[c1.id] <@ (SELECT c2.path FROM categories AS c2 WHERE c2.id=
(SELECT category_id FROM item_categories WHERE item_id=8 LIMIT 1)) order by depth
基于路径提取面包屑并且有效。
但我想获取所有面包屑(不只是一个)。删除 LIMIT 1
并更改 = to in
我将得到一个数组数组,而不仅仅是一个数组,并且会触发错误:
more than one row returned by a subquery used as an expression
这是正常的。
我想要的示例 - 项目在:
cat1 - > cat2 - >cat3
ca5 -> cat9
,以及来自数据库(这样我就可以遍历它们):
[ [{'name':cat1, 'slug':slug1}, {'name':cat2, 'slug':slug2}, {'name':cat3, 'slug':slug3}], [{'name':cat5, 'slug':slug5}, {'name':cat9, 'slug':slug9}]]
dbfiddle: https://dbfiddle.uk/?rdbms=postgres_10&fiddle=f756cfe568d38425dfe25cfec60b1b3f
因此,除了获得一个面包屑,我如何才能获得一个面包屑数组作为结果?
使用 json_build_object
, unnest
and ordered json_agg
:
select
c.id,
json_agg(
json_build_object('name',c2.name,'slug',c2.slug)
order by p.depth
)
from categories as c
inner join lateral unnest(c.path) with ordinality as p(id, depth) on true
inner join categories as c2 on
c2.id = p.id
where
exists (
select *
from item_categories as tt
where
tt.item_id = 1 and
tt.category_id = c.id
)
group by
c.id
或者如果需要,您可以使用 table 中的 depth
列:
select
c.id,
json_agg(
json_build_object('name',c2.name,'slug',c2.slug)
order by c2.depth
)
from categories as c
inner join categories as c2 on
c2.id = any(c.path)
where
exists (
select *
from item_categories as tt
where
tt.item_id = 1 and
tt.category_id = c.id
)
group by
c.id
我不喜欢 json_build_object
is that you have to name your columns explicitly doing double work, so I've tried to useto_json
instead. It works, but honestly, I'm not that familiar with this syntax when alias of the table is passed to the function as an argument (see Using Composite Types in Queries
) and could not make it work without lateral
加入:
select
c.id,
json_agg(to_json(d) order by c2.depth)
from categories as c
inner join categories as c2 on
c2.id = any(c.path)
cross join lateral (select c.name, c.slug) as d
where
exists (
select *
from item_categories as tt
where
tt.item_id = 1 and
tt.category_id = c.id
)
group by
c.id