使用 Ecto.Query 的递归 SQL 查询
Recursive SQL query with Ecto.Query
我有一个 categories
table 包含以下列:
id
name
parent_id (nullable)
还有一个 books
table,里面有一个 category_id
列。
我想要一个函数,它接受类别 ID 列表 (category_ids
) 和 returns 一个查询,该查询获取属于给定类别之一或其子类别的书籍(递归)。
我已经编写了一个 returns 给定类别的所有子项的查询。我可以使用它来获取 category_ids
类别的所有子类别并使用新列表。但它会向数据库发送多个查询,我想在一个查询中完成。这是查询:
with recursive cat_tree as (
select id,
name,
parent_id
from categories
where id =
union all
select child.id,
child.name,
child.parent_id
from categories as child
join cat_tree as parent on parent.id = child.parent_id
)
select *
from cat_tree;
已编辑
@raw_sql """
select id,
name,
parent_id
from categories
where id in (?)
union all
select child.id,
child.name,
child.parent_id
from categories as child
join cat_tree as parent on parent.id = child.parent_id
"""
def category_search_query(query, []), do: query
def category_search_query(query, category_ids) do
query
|> recursive_ctes(true)
|> with_cte("cat_tree", as: fragment(@raw_sql, ^category_ids))
|> join(:inner, [b], c in "cat_tree", on: c.id == b.category_id)
end
但是当我将 [12, 13]
(例如)传递给函数时,它会出现以下错误:
(DBConnection.EncodeError) Postgrex expected an integer in -9223372036854775808..9223372036854775807, got '\f\r'. Please make sure the value you are passing matches the definition in your table or in your query or convert the value accordingly.
但是当我只传递一个整数(而不是列表)时,它工作正常。
我会制作一个程序来获取类别列表作为参数(可以是数组)并将您的查询更改为:
create function funcName (categoryIds int[])
returns table ( bookid int ,categoryid int , ...<deffine book columns>)
as
$$
with recursive cat_tree as (
select
id,name,parent_id
from
categories
where id in (select unnest(categoryIds))
union all
select
child.id,child.name,child.parent_id
from
categories as child
join cat_tree as parent on parent.id = child.parent_id
)
select
b.*
from
cat_tree c
join books on c.id = b.categoryid
$$ Language sql;
我有一个 categories
table 包含以下列:
id
name
parent_id (nullable)
还有一个 books
table,里面有一个 category_id
列。
我想要一个函数,它接受类别 ID 列表 (category_ids
) 和 returns 一个查询,该查询获取属于给定类别之一或其子类别的书籍(递归)。
我已经编写了一个 returns 给定类别的所有子项的查询。我可以使用它来获取 category_ids
类别的所有子类别并使用新列表。但它会向数据库发送多个查询,我想在一个查询中完成。这是查询:
with recursive cat_tree as (
select id,
name,
parent_id
from categories
where id =
union all
select child.id,
child.name,
child.parent_id
from categories as child
join cat_tree as parent on parent.id = child.parent_id
)
select *
from cat_tree;
已编辑
@raw_sql """
select id,
name,
parent_id
from categories
where id in (?)
union all
select child.id,
child.name,
child.parent_id
from categories as child
join cat_tree as parent on parent.id = child.parent_id
"""
def category_search_query(query, []), do: query
def category_search_query(query, category_ids) do
query
|> recursive_ctes(true)
|> with_cte("cat_tree", as: fragment(@raw_sql, ^category_ids))
|> join(:inner, [b], c in "cat_tree", on: c.id == b.category_id)
end
但是当我将 [12, 13]
(例如)传递给函数时,它会出现以下错误:
(DBConnection.EncodeError) Postgrex expected an integer in -9223372036854775808..9223372036854775807, got '\f\r'. Please make sure the value you are passing matches the definition in your table or in your query or convert the value accordingly.
但是当我只传递一个整数(而不是列表)时,它工作正常。
我会制作一个程序来获取类别列表作为参数(可以是数组)并将您的查询更改为:
create function funcName (categoryIds int[])
returns table ( bookid int ,categoryid int , ...<deffine book columns>)
as
$$
with recursive cat_tree as (
select
id,name,parent_id
from
categories
where id in (select unnest(categoryIds))
union all
select
child.id,child.name,child.parent_id
from
categories as child
join cat_tree as parent on parent.id = child.parent_id
)
select
b.*
from
cat_tree c
join books on c.id = b.categoryid
$$ Language sql;