Blog

Ecto: invalid expression for join `:on`, subqueries aren’t supported, left_join con subquery

Ecto: invalid expression for join `:on`, subqueries aren’t supported, left_join con subquery

El otro día estaba intentando juntar una fila de un id de una tabla «Graphs» con una columna de otra tabla de eventos. Primero intenté utilizar un join con subquery en el on:

from g in Graph,
    left_join: ue in Event,
    on: g.id == ^id and ue.inserted_at == fragment(
      "COALESCE(?, 'NULL')",
       subquery(TdDd.Lineage.Units.last_updated_query())
    ),
    select:  %{graph: g, unit_last_updated: ue.inserted_at}

El left join con el COALESCE NULL es simplemente para poder obtener un grafo en el caso de que no haya ningún evento.

Sin embargo, esta query generaba el siguiente error:

ecto invalid expression for join `:on`, subqueries aren't supported

… en PostgreSQL se pueden introducir subqueries en el on, pero Ecto no lo soporta.

Luego hice un left join con on: true

from g in Graph,
    left_join: ue in Event, on: true,
    where: g.id == ^id and ue.inserted_at == fragment(
      "COALESCE(?, 'NULL')",
      subquery(TdDd.Lineage.Units.last_updated_query())
    ),
    select:  %{graph: g, unit_last_updated: ue.inserted_at}

Sin embargo, vi aquí que se hacer directamente un join con una subquery (Units.last_updated_query(), que sólo devuelve una fila):

    # convoluted left join with a last unit event one row table just to get
    # this information together with the searched graph, in one query.

    query =
      from g in Graph,
        left_join: ue in subquery(Units.last_updated_query()),
        where: g.id == ^id,
        select: %{graph: g, unit_last_updated: ue.inserted_at}

que resulta en:

SELECT g0.id, g0.hash, g0.params, g0.data, g0.inserted_at, g0.updated_at, s1.inserted_at FROM "graphs" AS g0
LEFT OUTER JOIN (
  SELECT su0.inserted_at AS inserted_at FROM unit_events AS su0 WHERE (
    su0."event" IN ('LoadSucceeded_','Deleted_')
  ) ORDER BY su0."inserted_at" DESC LIMIT 1
) AS s1 ON TRUE WHERE (g0."id" = 1309)

Mucho más limpio…