Greetings, everyone!
I’m trying to translate this SQL query into Ecto but it’s kicking me in the cheeks:
WITH RECURSIVE tree AS (
SELECT id, parent_id, name
FROM tags
WHERE id = $1
UNION ALL
SELECT child.id, child.parent_id, child.name
FROM tags child
JOIN tree parent ON parent.id = child.parent_id
)
SELECT *
FROM tree
It’s a simple table containing only the three fields in the SELECT
statement.
I’ve tried various ideas that popped up while reading the documentation, including using fragment/1
and with_cte/3
, but the best I’ve been able to produce so far is compiler errors.
Thanks in advance for your help.
3 Likes
I have rarely used with_cte
but never had issues, what is the problem you are witnessing exactly?
Is this your full fragment code? Or is it like the below?
order_by: fragment(
"""
(
WITH RECURSIVE tree AS (
SELECT id, parent_id, name
FROM tags
WHERE id = $1
UNION ALL
SELECT child.id, child.parent_id, child.name
FROM tags child
JOIN tree parent ON parent.id = child.parent_id
)
SELECT *
FROM tree
)
"""
If I recall correctly, you need brackets and “”" around the WITH RECURSIVE to get it to work properly without throwing errors. I was messing around with this last month so may be wrong.
Either way, I ended up just using this instead.
@comment_tree """
SELECT id, parent_id, ARRAY[id] AS path
FROM comments
WHERE parent_id IS NULL
UNION ALL
SELECT c.id, c.parent_id, ct.path || c.id
FROM comments AS c
JOIN comment_tree AS ct ON ct.id = c.parent_id
"""
def list_replies(comments) do
Comment
|> recursive_ctes(true)
|> with_cte("comment_tree", as: fragment(@comment_tree))
|> join(:inner, [c], ct in "comment_tree", on: ct.id == c.id)
|> select([c, ct], %{c | id: c.id})
|> order_by([c, ct], ct.path)
|> Repo.all()
end
The above obviously isnt the full code, but its part of the code that lets create a recursive comment tree like in the below image.
4 Likes
Thanks for your help! Your suggestion worked. The problem was that I had my SQL fragment defined as a function variable instead of as a module attribute, which caused this compiler error:
** (Ecto.Query.CompileError) to prevent SQL injection attacks, fragment(...) does not allow strings to be interpolated as the first argument via the `^` operator, got: `tag_tree`