Ecto JOIN осложнения для запроса таблицы только для добавления - PullRequest
0 голосов
/ 03 июня 2019

Я пытаюсь запросить таблицу Ecto с семантикой только для добавления, поэтому я бы хотел самую последнюю версию полной строки для данного идентификатора.Методика описана здесь , но вкратце: я хочу присоединиться к самой таблице с помощью подзапроса, который выбирает самое последнее время для идентификатора.В SQL это будет выглядеть так:

SELECT r.*
FROM rules AS r
JOIN (
  SELECT id, MAX(inserted_at) AS inserted_at FROM rules GROUP BY id
) AS recent_rules
ON (
  recent_rules.id = r.id
  AND recent_rules.inserted_at = r.inserted_at)

У меня проблемы с расшифровкой в ​​Ecto.Я пробовал что-то вроде этого:

maxes =
  from(m in Rule,
    select: {m.id, max(m.inserted_at)},
    group_by: m.id)

from(r in Rule,
  join: m in ^maxes, on: r.id == m.id and r.inserted_at == m.inserted_at)

Но пытаясь запустить это, я столкнулся с ограничением:

запросы в объединениях могут иметь только условия where в запросе

предложение maxes должно быть просто формой SELECT _ FROM _ WHERE.

Если я попытаюсь переключить maxes и Rule в JOIN:

maxes =
  from(m in Rule,
    select: {m.id, max(m.inserted_at)},
    group_by: m.id)

from(m in maxes,
  join: r in Rule, on: r.id == m.id and r.inserted_at == m.inserted_at)

, тоЯ не могу SELECT весь ряд, просто id и MAX(inserted_at).

Кто-нибудь знает, как сделать это JOIN?Или лучший способ сделать запрос на добавление только в Ecto?Спасибо 10

1 Ответ

2 голосов
/ 03 июня 2019

Выполнение m in ^maxes - это не запуск подзапроса, а либо составление запроса (если оно в операторе from), либо преобразование запроса в соединение (в объединении). В обоих случаях вы меняете один и тот же запрос. Учитывая ваш начальный запрос, я думаю, что вы хотите подзапросы.

Также обратите внимание, что подзапрос требует select для возврата карты, поэтому мы можем обратиться к полям позже. Что-то вроде этого должно работать:

maxes =
  from(m in Rule,
    select: %{id: m.id, inserted_at: max(m.inserted_at)},
    group_by: m.id)

from(r in Rule,
  join: m in ^subquery(maxes), on: r.id == m.id and r.inserted_at == m.inserted_at)

PS: Я выдвинул коммит в Ecto, который разъясняет сообщение об ошибке в таких случаях, как ваш.

invalid query was interpolated in a join.
If you want to pass a query to a join, you must either:

  1. Make sure the query only has `where` conditions (which will be converted to ON clauses)
  2. Or wrap the query in a subquery by calling subquery(query)
...