我有一个列表,我想使用where
s来转换or
子句:
my_list = [
%{min: 1, max: 10},
%{min: 4, max: 16},
%{min: 5, max: 21}
]
我打算构建的where
子句将成为另一个更大的查询的一部分。
现在我必须编写以下代码(注意重复):
query =
my_list
|> Enum.with_index()
|> Enum.reduce(bigger_query, fn {item, index}, q ->
if index == 0 do
where(q, [table], fragment("? BETWEEN ? AND ?", table.age, ^item["min"], ^item["max"]))
else
or_where(q, [table], fragment("? BETWEEN ? AND ?", table.age, ^item["min"], ^item["max"]))
end
end)
可以在Ecto术语中更简单地重写此查询吗?如果是,怎么做?
更新即可。考虑这个例子:
query = from posts in Post, where: posts.author_id == ^12
query =
my_list
|> Enum.with_index()
|> Enum.reduce(bigger_query, fn {item, index}, q ->
if index == 0 do
where(q, [posts], fragment("? BETWEEN ? AND ?", posts.author_age, ^item["min"], ^item["max"]))
else
or_where(q, [posts], fragment("? BETWEEN ? AND ?", posts.author_age, ^item["min"], ^item["max"]))
end
end)
query = where(q, [posts], posts.published == ^true)
正确生成查询:
SELECT * FROM posts WHERE author_id = 12 AND ((age BETWEEN 1 AND 10) OR (age BETWEEN 4 AND 16) AND (age BETWEEN 5 AND 21))
实现此目标的最紧凑的Ecto代码是什么?
答案 0 :(得分:0)
您不需要将第一个条件放在where
中。即使查询中已有or_where
,where
也能正常运行。以下应该可以正常工作:
query = Enum.reduce(my_list, bigger_query, fn item, q ->
or_where(q, [table], fragment("? BETWEEN ? AND ?", table.age, ^item["min"], ^item["max"]))
end)
您可以使用模式匹配进一步简化此操作(假设键是字符串,并且您将错误中的原子作为键放在问题的第一个代码段中):
query = Enum.reduce(my_list, bigger_query, fn %{"min": min, "max": max}, q ->
or_where(q, [table], fragment("? BETWEEN ? AND ?", table.age, ^min, ^max))
end)