I have two tables. One with a parent child hierarchy and one with the details of some leaves somewhere in the paths.
create table category (
category_id integer,
category_name text,
parent_category integer,
level integer);
insert into category values
(1, 'cat1', null, 1),
(2, 'cat2', null, 1),
(3, 'cat3', 1, 2),
(4, 'cat4', 1, 2),
(5, 'cat5', 1, 2),
(6, 'cat6', 4, 3),
(7, 'cat7', 4, 3),
(8, 'cat8', 3, 3),
(9, 'cat9', 3, 3),
(10, 'cat10', 5, 3),
(11, 'cat11', 5, 3);
create table photo(
id integer,
value text
);
insert into photo values
(6,'photo'),
(9,'photo'),
(11,'photo');
I am looking for a way to return the hierarchy of but only the paths which have a photo in the second table.
WITH RECURSIVE cte AS (
SELECT category_id, category_name, parent_category, 1 AS level
FROM category
where level = 1
UNION ALL
SELECT c.category_id, c.category_name, c.parent_category, ct.level + 1
FROM cte ct
JOIN category c ON c.parent_category = ct.category_id
)
SELECT category_id,category_name,parent_category,value
FROM cte
full join photo on cte.category_id = photo.id
The above query returns the whole hierarchy including possibly a photo:
(* the rows I do not want)
|category_id | category_name | parent_category | value |
|------------|---------------|-----------------|-------|
| 1 | cat1 | | |
| 2 | cat2 | | |*
| 3 | cat3 | 1 | |
| 4 | cat4 | 1 | |
| 5 | cat5 | 1 | |
| 6 | cat6 | 4 | photo |
| 7 | cat7 | 4 | |*
| 8 | cat8 | 3 | |*
| 9 | cat9 | 3 | photo |
| 10 | cat10 | 5 | |*
| 11 | cat11 | 5 | photo |
How do I only return the hierarchy path where the ‘leaves’ got a photo:
|category_id | category_name | parent_category | value |
|------------|---------------|-----------------|-------|
| 1 | cat1 | | |
| 3 | cat3 | 1 | |
| 4 | cat4 | 1 | |
| 5 | cat5 | 1 | |
| 6 | cat6 | 4 | photo |
| 9 | cat9 | 3 | photo |
| 11 | cat11 | 5 | photo |
I created a db fiddle for it: https://dbfiddle.uk/uoYXPzJ7
Initial thought where to use some sort of indexing like gist and ltree to help in my aid?
2
Answers
Start with only the categories that have a photo, then recurse upwards to their parents. Use
UNION
instead ofUNION ALL
to remove duplicates (i.e. categories that are the parent of multipe child categories):(updated fiddle)
The recursive CTE must remove duplicate parent nodes by the use of
UNION
instead ofUNION ALL
.You can do:
Result:
See fiddle.