仅追加 table 查询的 Ecto JOIN 并发症
Ecto JOIN complications for append-only table query
我正在尝试查询具有仅附加语义的 Ecto table,所以我想要 最新 版本的完整行ID。该技术是 described here,但简而言之:我想加入一个 table 本身,并使用一个子查询获取 ID 的最近时间。在 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)
但是尝试运行这个,我遇到了一个限制:
queries in joins can only have where
conditions in query
建议 maxes
必须只是一个 SELECT _ FROM _ WHERE
形式。
如果我尝试在 JOIN 中切换 maxes
和 Rule
:
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 中查询仅追加的更好方法?谢谢
执行 m in ^maxes
不是 运行 子查询,而是查询组合(如果在 from 中)或将查询转换为连接(在连接中)。在这两种情况下,您都在更改相同的查询。鉴于您的初始查询,我相信您需要子查询。
另请注意,子查询需要 select
到 return 映射,因此我们稍后可以引用这些字段。按照这些思路应该可以工作:
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)
我正在尝试查询具有仅附加语义的 Ecto table,所以我想要 最新 版本的完整行ID。该技术是 described here,但简而言之:我想加入一个 table 本身,并使用一个子查询获取 ID 的最近时间。在 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)
但是尝试运行这个,我遇到了一个限制:
queries in joins can only have
where
conditions in query
建议 maxes
必须只是一个 SELECT _ FROM _ WHERE
形式。
如果我尝试在 JOIN 中切换 maxes
和 Rule
:
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 中查询仅追加的更好方法?谢谢
执行 m in ^maxes
不是 运行 子查询,而是查询组合(如果在 from 中)或将查询转换为连接(在连接中)。在这两种情况下,您都在更改相同的查询。鉴于您的初始查询,我相信您需要子查询。
另请注意,子查询需要 select
到 return 映射,因此我们稍后可以引用这些字段。按照这些思路应该可以工作:
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)