多个OR子句

时间:2017-02-13 14:39:49

标签: postgresql elixir where-clause ecto

我有一个列表,我想使用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代码是什么?

1 个答案:

答案 0 :(得分:0)

您不需要将第一个条件放在where中。即使查询中已有or_wherewhere也能正常运行。以下应该可以正常工作:

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)