如何将此 SQL join 语句转换为 Ecto 查询?

How to translate this SQL join statement into an Ecto query?

我有一个 SQL 查询 returns 任何其他用户(即 "only show me the most recent message sent to me by each message sender")发送给用户的唯一最新消息。在纯 SQL 中,我可以按如下方式完成这项工作:

select messages.* from messages
join
(select max(inserted_at) maxtime,sender_id from messages group by sender_id) latest
on messages.inserted_at=latest.maxtime and messages.sender_id=latest.sender_id and messages.receiver_id=2;

关于如何将这样的嵌套连接语句转换为惯用的 Ecto 查询有什么想法吗?

经过一些挖掘,我发现我可以使用纯 Ecto 语法在连接中使用 subquery 来做到这一点,如下所示:

user_id = 2

subquery = from(s in Message,
                select: %{ sender_id: s.sender_id, max_time: max(s.inserted_at) },
                where: s.receiver_id == ^user_id,
                group_by: s.sender_id
               )

query = from(m in Message,
             join: s in subquery(subquery), on: m.inserted_at == s.max_time and m.sender_id == s.sender_id,
             where: m.receiver_id == ^user_id
            )

Repo.all(query)

对于那些感兴趣的人,当您检查查询以查看 SQL 是什么样子时,这里是输出:

 > Ecto.Adapters.SQL.to_sql(:all, Repo, query)
 {"SELECT m0.\"id\", m0.\"sender_id\", m0.\"receiver_id\", m0.\"body\", m0.\"received_at\", m0.\"inserted_at\" FROM \"messages\" AS m0 INNER JOIN (SELECT m0.\"sender_id\" AS \"sender_id\", max(m0.\"inserted_at\") AS \"max_time\" FROM \"messages\" AS m0 WHERE (m0.\"receiver_id\" = ) GROUP BY m0.\"sender_id\") AS s1 ON (m0.\"inserted_at\" = s1.\"max_time\") AND (m0.\"sender_id\" = s1.\"sender_id\") WHERE (m0.\"receiver_id\" = )", [30064, 30064]}

不太漂亮SQL,但当我尝试它时in a SQL fiddle它运行基本上相同的执行游戏,执行时间相同!

感谢@radzserg whose answer to this question 让我找到了缺失的子查询。奇怪的是,这个问题的措辞和结构 几乎与我的完全相同,但一年前获得了 3 票赞成,而我的 4 票反对。希望这不会预示 Elixir/Ecto 社区对待试图掌握事物的初学者的方式会发生变化!