Как я могу увидеть необработанный SQL, сгенерированный для Ecto.Query?

У меня есть Ecto.Query и Repo, так что я могу вызвать Repo.all(query) и получить результаты. Однако результаты не такие, как я ожидаю.

Как я могу увидеть необработанный SQL, который Repo сгенерирует из Ecto.Query?


person Nathan Long    schedule 21.04.2016    source источник


Ответы (4)


Вы можете использовать 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", []}

Эта функция также доступна в репозитории с именем to_sql, если вы используете адаптер на основе 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]}
person Gazler    schedule 21.04.2016
comment
Спасибо. В моем случае мне нужно было передать структуру query вместо Post. - person Nathan Long; 21.04.2016
comment
@NathanLong Вы можете передать все, что реализует протокол Queryable. Это включает в себя запрос (очевидно), а также все, что использует Ecto.Schema. Я обновлю свой ответ. - person Gazler; 21.04.2016
comment
Последующий вопрос: stackoverflow .com/questions/41021546/ - person Nathan Long; 07.12.2016
comment
Начиная с Ecto 3, часть sql была разделена на ecto_sql. Вот обновленная ссылка hexdocs.pm/ecto_sql/3.0 .3/Ecto.Adapters.SQL.html#to_sql/3 для будущих пользователей Google. - person Chase; 18.12.2018

Удобный вспомогательный метод для печати необработанного 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
person Dan Andreasson    schedule 13.07.2018
comment
Это не работает для отношений или предварительных загрузок. В моем случае вы получаете только запрос родительского уровня. - person AlxVallejo; 24.06.2019
comment
@DanAndreasson Не могли бы вы помочь мне здесь: stackoverflow.com/questions/65183075/ - person Tab Key; 08.12.2020

to_sql/2 добавляется в модуль, на котором вы use 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]}
person Gjaldon    schedule 16.10.2019
comment
На Эликсире 1.7.3 я получаю Repo.to_sql/3 is undefined or private - person AlxVallejo; 03.12.2019
comment
@AlxVallejo Это не Repo.to_sql/3, а MyApp.Repo.to_sql/2. Это должно работать с Ecto 3 или, может быть, даже раньше. - person Gjaldon; 04.12.2019

Это в основном ответ Gazler, но измененный для использования в коде:

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

Вы можете использовать простой IO.inspect, но он выведет запрос с обратной косой чертой.

person denis.peplin    schedule 28.10.2018
comment
Я получаю Ecto.Queryable нереализованные ошибки для каждой из моих реляционных моделей запроса. Нужно ли их предварительно загружать? Кажется странным, что мне нужно предварительно загрузить. - person AlxVallejo; 24.06.2019