nested sets — очень такое себе: на небольших объёмах ещё как-то приемлемо, но потом вставка-удаление понемногу начинают превращаться в кошмар, и чем дальше, тем хуже =)
простейшая структура дерева как у тебя — adjacency list — и рекурсивный запрос будут работать очень быстро.
SELECT *
FROM categories cat
CROSS JOIN LATERAL (
WITH RECURSIVE tree AS (
SELECT cat.cat_id AS cat_id
UNION ALL
SELECT c.cat_id FROM tree t, categories c WHERE c.cat_parent = t.cat_id
)
SELECT cat_id FROM tree
) tree
INNER JOIN products prd USING(prd_id)
WHERE cat_parent IS NULL
как-то так,
но лучше всего сделать функцию
categories_children_id(root INT)
и утащить рекурсивный запрос туда. эта функция много где пригодится, когда с категориями работать будешь