如何查看生成的 Ecto.Query 的原始 SQL?

50
我有一个Ecto.Query和一个Repo,我可以调用Repo.all(query)获取结果。但是,结果并不是我所期望的。
如何查看 Repo 将从 Ecto.Query 生成的原始SQL?
4个回答

80
您可以使用 Ecto.Adapters.SQL.to_sql/3
iex> Ecto.Adapters.SQL.to_sql(:all, Repo, Post)
{"SELECT p.id, p.title, p.inserted_at, p.created_at FROM posts as p", []}

如果您正在使用基于 SQL 的适配器,该函数也可以在具有名称 to_sql 的存储库下使用:

 iex> Repo.to_sql(:all, Post)
  {"SELECT p.id, p.title, p.inserted_at, p.created_at FROM posts as p", []}

查询可以是任何实现Ecto.Queryable协议的结构,例如上面的Post(它是一个导入了Ecto.Schema模块的模块)。也可以传递一个Ecto.Query

iex> query = Ecto.Query.where(Post, [p], p.views > 10)
iex> Ecto.Adapters.SQL.to_sql(:all, Repo, query)
{"SELECT p.id, p.title, p.inserted_at, p.created_at FROM posts as p WHERE p.views > $1", [10]}

谢谢。在我的情况下,我需要传递query结构体代替Post - Nathan Long
@NathanLong 你可以传递任何实现了Queryable协议的东西。这包括一个查询(显然),但也包括任何使用Ecto.Schema的东西。我会更新我的回答。 - Gazler
跟进问题:http://stackoverflow.com/questions/41021546/can-i-get-ecto-to-log-raw-sql - Nathan Long
1
从 Ecto 3 开始,SQL 部分被拆分为 ecto_sql。这是更新后的链接 https://hexdocs.pm/ecto_sql/3.0.3/Ecto.Adapters.SQL.html#to_sql/3,供未来的谷歌搜索者使用。 - Chase

17

一个方便的辅助方法,用于打印原始SQL语句

def print_sql(queryable) do
  IO.inspect(Ecto.Adapters.SQL.to_sql(:all, Repo, queryable))
  queryable
end

def list_new_foos() do
  Foo
  |> where([foo], foo.bar == 1337)
  |> limit(100)
  |> print_sql
  |> Repo.all()
end

这对于关系或预加载不起作用。在我的情况下,您只能获得父级查询。 - AlxVallejo
@DanAndreasson,你能帮我解决这个问题吗:https://stackoverflow.com/questions/65183075/add-interval-to-timestamp-using-ecto-fragments/ - Tab Key

4

to_sql/2被添加到了你所使用的Ecto.Repo模块中。按照惯例,该模块应该被命名为MyApp.Repo(其中MyApp是你的应用程序名称)。在内部,它将使用Ecto.Adapters.SQL.to_sql/3,但Ecto.Adapters.SQL更多地是一个内部模块。

使用它看起来像这样:

iex> query = Ecto.Query.where(Post, [p], p.views > 10)
iex> MyApp.Repo.to_sql(:all, query)
{"SELECT p.id, p.title, p.inserted_at, p.created_at FROM posts as p WHERE p.views > $1", [10]}

在 Elixir 1.7.3 上,我得到了 Repo.to_sql/3 未定义或私有 的错误。 - AlxVallejo
@AlxVallejo,不是Repo.to_sql/3,而是MyApp.Repo.to_sql/2。它应该可以与Ecto 3甚至更早的版本一起使用。 - Gjaldon

2

这基本上是 Gazler 的回答,但修改为可在代码中使用:

query = from p in Post
{query, params} = Ecto.Adapters.SQL.to_sql(:all, Repo, query)
IO.puts("#{query}, #{inspect(params)}")

您可以使用简单的IO.inspect,但它会输出带有反斜杠的查询。


我的查询中,每个关系模型都出现了“Ecto.Queryable未实现”的错误。我需要先预加载它们吗?这似乎很奇怪,我为什么需要预加载。 - AlxVallejo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接