TL;DR:
Is there a way, without resorting to large fragments for a CTE to add a depth
or level
field to a recursive CTE as described here?
Longer story:
If you want to know why I want to do this without a fragment, the answer is I want to take two Ecto queries that can be filtered independently and then use union_all/2
to put them together.
I restructured the fragment to work entirely with Ecto queries using this with_cte/3
and it works great!
Well, it works great with one exception. A lot of recursive queries use a depth
or level
field as a strategy for for limited recursion and preventing infinite recursion. See this post for an example.
The trouble comes from needing to SELECT
a thing I don’t know how to select in SQL. In the example you have these:
WITH RECURSIVE t(item_id, json, level)
I don’t see any way to get named columns for a CTE. It appears to only work through inference in Ecto.
And:
SELECT parent.item_id, to_jsonb(parent) || jsonb_build_object( 'children', t.json ), level + 1
I cannot see a way to add an arbitrary select to an existing query, like level + 1
.
I see that with_cte/3
has an example of where I can pass in a tuple like so:
{"category_tree", Category}
|> recursive_ctes(true)
|> with_cte("category_tree", as: ^category_tree_query)
|> join(:left, [c], p in assoc(c, :products))
|> group_by([c], c.id)
|> select([c, p], %{c | products_count: count(p.id)})
I feel like the answer might be in here but I’m missing something.
Admittedly, CTEs and recursion are two things I use so rarely in SQL it’s a situation of “find an example and mess with it until it works as expected.” So it’s quite possible there’s something fundamental I’m missing in all of this. (SELECT level + 1
in the example kinda blows my mind.)