add batch remove batch split batch comment selection show hidden batches hide batch highlight batch
db<>fiddle
donate feedback about
By using db<>fiddle, you agree to license everything you submit by Creative Commons CC0.
Help with an interesting Postgres question: Why isn't an Index Only Scan used on a partition accessed via the parent table?.
select version();
version
PostgreSQL 15.0 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 8.5.0 20210514 (Red Hat 8.5.0-10), 64-bit
SELECT 1
CREATE TABLE assets (
id serial,
name text,
owner text,
PRIMARY KEY(id)
);

CREATE TABLE users (
id serial,
username text,
ref1 text,
ref2 text,
PRIMARY KEY(id)
);

INSERT INTO assets (name, owner) VALUES
('#1', 'a'),
('#2', 'b'),
('#3', 'c'),
('#4', 'a'),
('#5', 'c'),
('#6', 'd'),
('#7', 'e'),
('#8', 'd'),
('#9', 'a'),
('#10', 'a'),
('#11', 'z')
;

INSERT INTO users (username, ref1, ref2) VALUES
('bobo', 'a', 'd'),
('toto', 'b', 'e'),
('momo', 'c', 'd'),
('lolo', 'a', 'f'),
('popo', 'c', 'f');

CREATE TABLE
CREATE TABLE
INSERT 0 11
INSERT 0 5
CREATE TABLE
INSERT 0 3
with recursive
nodes as (
select u.id, r.ref
from users u
cross join lateral ( values (u.ref1), (u.ref2) ) r(ref)
),
edges as (
select distinct n1.id as id1, n2.id as id2
from nodes n1
inner join nodes n2 on n1.ref = n2.ref
),
rcte as (
select id1, id2, array[id1] as visited from edges where id1 = id2
union all
select r.id1, e.id2, r.visited || e.id2
from rcte r
inner join edges e on e.id1 = r.id2
where e.id2 <> all(r.visited)
),
groups as (
select id1 as id, array_agg(distinct id2 order by id2) as ids
from rcte
group by id1
)
select * from groups order by id
id ids
1 {1,3,4,5}
2 {2}
3 {1,3,4,5}
4 {1,3,4,5}
5 {1,3,4,5}
SELECT 5
with recursive
nodes as (
select u.id, r.ref
from users u
cross join lateral ( values (u.ref1), (u.ref2) ) r(ref)
),
edges as (
select distinct n1.id as id1, n2.id as id2
from nodes n1
inner join nodes n2 on n1.ref = n2.ref
),
rcte as (
select id1, id2, array[id1] as visited from edges where id1 = id2
union all
select r.id1, e.id2, r.visited || e.id2
from rcte r
inner join edges e on e.id1 = r.id2
where e.id2 <> all(r.visited)
),
groups as (
select id1 as id, array_agg(distinct id2 order by id2) as ids
from rcte
group by id1
)
select g.ids,
array_agg(distinct u.username) as usernames,
array_agg(distinct u.ref1) as refs1,
case when g.ids is null then array_agg(distinct a.owner) else array_agg(distinct u.ref2) end as refs2,
array_agg(distinct a.id) as asset_ids,
count(distinct a.id) as asset_count
from assets a
left join users u on a.owner in (u.ref1, u.ref2)
left join groups g on g.id = u.id
group by g.ids

ids usernames refs1 refs2 asset_ids asset_count
{1,3,4,5} {bobo,lolo,momo,popo} {a,c} {d,f} {1,3,4,5,6,8,9,10} 8
{2} {toto} {b} {e} {2,7} 2
null {NULL} {NULL} {z} {11} 1
SELECT 3