javvvva javvvva - 2 months ago 25
SQL Question

Passing raw SQL query as an argument to Repo.all() in Ecto

Ecto.Adapters.SQL.query(Repo, "Select * from table", [])
seems to execute the query and returns the data. Is there a way to define a query based on raw sql such that it can be passed to
Repo.all()
as an argument?

I'm looking for something like,

qry = Ecto.Adapters.SQL.query("select * from table", []) # This doesn't work
Repo.all(qry)

Answer

You cannot pass raw sql to Repo.all like this.
Best you can do is pass some unsupported database function as fragment or find workaround.

#UNION ALL
iex(1)> result1 = Model1 |> select([m], m.title) |> Repo.all
["a", "b"]
iex(2)> result2 = Model2 |> select([m], m.title) |> Repo.all
["a", "c"]
iex(3)> result1 ++ result2
["a", "b", "a", "c"]

#UNION
iex(1)> result1 = Model1 |> select([m], m.title) |> Repo.all
["a", "b"]
iex(2)> result2 = Model2 |> select([m], m.title) |> Repo.all
["a", "c"]
iex(3)> (result1 ++ result2) |> Enum.uniq
["a", "b", "c"]

#UNION USING RAW SQL
iex(1)> query = "select title from models1 union select title from model2"
...
iex(2)> {:ok, %Postgrex.Result{columns: columns, rows: rows}} = Ecto.Adapters.SQL.query(Repo, query, [])
...
iex(3)> rows |> Enum.map(&Enum.zip(columns, &1)) |> Enum.map(&Enum.into(&1, %{})) 
[%{"title" => "a"}, %{"title" => "b"}, %{"title" => "c"}]