versilov

versilov

Sub-selects in ecto queries

How can I write this query in Ecto?

SELECT 
    *,
    (SELECT COUNT(o.id) FROM tenant_versilov.orders o 
               LEFT OUTER JOIN tenant_versilov.shipments s ON s.order_id = o.id
               WHERE o.company_id = c.id AND s.id IS NULL AND NOT o.archived) orders_count,
    (SELECT COUNT(s.id) FROM tenant_versilov.shipments s
               LEFT OUTER JOIN tenant_versilov.orders o ON s.order_id = o.id
              WHERE o.company_id = c.id AND s.batch_id IS NULL) shipments_count        
FROM tenant_versilov.companies c
WHERE c.active = TRUE;

The closest approach is to use select_merge with fragments, but fragments do not allow to interpolate strings to set schemas:

query
|> select_merge([c], %{
      shipments_count:
        fragment(
           "(SELECT COUNT(s.id) FROM tenant_versilov.shipments s
                            LEFT OUTER JOIN tenant_versilov.orders o ON s.order_id = o.id
                            WHERE o.company_id = c0.id AND s.batch_id IS NULL)"
      )

Marked As Solved

versilov

versilov

With minor modifications it worked, thanks!
Had to add group_by and coalesce to deal with nil count values.
Here is the final working query:

   orders_query =
      from(o in Order,
        left_join: s in assoc(o, :shipments),
        where: not o.archived and is_nil(s.id),
        group_by: o.company_id,
        select: %{company_id: o.company_id, count: count()}
      )

    shipments_query =
      from(s in Shipment,
        inner_join: o in assoc(s, :order),
        where: is_nil(s.batch_id),
        group_by: o.company_id,
        select: %{company_id: o.company_id, count: count()}
      )

    Company
    |> filter_by_user(user)
    |> only_active(true)
    |> join(:left, [c], o in subquery(orders_query), on: o.company_id == c.id)
    |> join(:left, [c], s in subquery(shipments_query), on: s.company_id == c.id)
    |> group_by([c, o, s], [c.id, o.count, s.count])
    |> select_merge([c, o, s], %{
      orders_count: coalesce(o.count, 0),
      shipments_count: coalesce(s.count, 0)
    })
    |> Repo.all(prefix: tenant)

Also Liked

hauleth

hauleth

What you probably want is something like:

SELECT
  c.*,
  orders.count,
  s.count
FROM companies c
INNER JOIN (SELECT o.company_id company_id, COUNT(*) count
            FROM orders o
            LEFT OUTER JOIN shipments s ON s.order_id = o.id
            WHERE s.id IS NULL AND NOT o.archived
            GROUP BY o.company_id) orders
    ON orders.company_id = c.id
-- and so on

So in Elixir it would be like:

orders_query =
  from o in Order,
    left_outer_join: s in assoc(o, :shipments),
    where: not o.archived and is_nil(s.id),
    group_by: o.company_id,
    select: %{id: o.company_id, count: count()}

shipments_query =
  from s in Shipment,
    left_inner_join: o in assoc(sh, :order),
    where: is_nil(s.batch_id),
    select: %{id: o.company_id, count: count()}

from c in Company,
  left_inner_join: o in subquery(orders_query), on: o.id == c.id,
  left_inner_join: s in subquery(shipments_query), on: s.id == c.id,
  select_merge: %{orders_count: o.count, shipments_count: s.count}

Where Next?

Popular in Questions Top

electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
mcarvalho
What is the difference between System.get_env and Application.get_env? For example, what are best practices to use one versus another.
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
JorisKok
I have a server on AWS, and was running a load test using artillery. When looking at the Phoenix dashboard I see the Ports going to 100% ...
New

Other popular topics Top

openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 31586 112
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New

We're in Beta

About us Mission Statement