【问题标题】:Ecto Elixir: Sum values in preloaded associationEcto Elixir:预加载关联中的总和值
【发布时间】:2018-04-20 09:09:03
【问题描述】:

我有一个数据库,其中包含可以有多个请求的不同歌曲,并且每个请求部分可以有多个投票。

我正在尝试构建一个查询来获取请求的所有信息(歌曲信息和用户投票),但我只想选择我需要的重要信息。

我现在是这样设置的

def get_requests_in_zone(zone_id, max_played) do
query = from request in Request,
  left_join: song in assoc(request, :song),
  where: request.zone_id == ^zone_id and request.times_played <= ^max_played,
  select: request,
  preload: [song: song],
  order_by:  [asc: request.times_played, desc: request.inserted_at]
Repo.all(query)
 end

def  calculate_rating(request_id)do
query = from votes in Vote,
  where: votes.request_id == ^request_id,
  select: sum(votes.rating)

Repo.one(query)
end

def get_requests_in_zone_with_votes(zone_id,max_played) do
Enum.map(get_requests_in_zone(zone_id,max_played),
  fn(x) ->
    %{title: x.song.title, url: x.song.url, thumbnail: x.song.thumbnail, rating: calculate_rating(x.id)} end)
end

但这会产生多个查询来计算每个请求的评分。我尝试构建一个查询,类似于:

def get_requests_in_zone(zone_id, max_played) do
query = from song in Song,
  left_join: request in assoc(song, :requests),
  join: votes in assoc(request, :votes), 
where: request.zone_id == ^zone_id and request.times_played <= ^max_played,
  select: %{title: song.title, url: song.url, thumbnail: song.thumbnail, rating: sum(votes.rating)},
  preload: [requests: {request, votes: votes}],
  order_by:  [asc: request.times_played, desc: request.inserted_at]
Repo.all(query)
end

但它没有用......发出这个错误消息

** (Ecto.QueryError) 字段.Song.request 预加载不是查询中的关联:

所以我决定通过将选择行更改为

来在选择中添加完整的歌曲
  select: %{song: song, rating: sum(votes.rating)},

它只是说 ERROR 42803 (grouping_error): 列“s0.id”必须出现在 GROUP BY 子句中或在聚合函数中使用

我如何构建一个查询来检索请求并返回类似于 get_requests_in_zone_with_votes 中使用的结构?

感谢您的宝贵时间。

【问题讨论】:

  • "但它不起作用..." 是否导致编译错误?运行时错误?还是给出了错误的结果?
  • 我刚刚更新了这个问题。但它只是说:ERROR 42803(grouping_error):列“s0.id”必须出现在GROUP BY子句中或在聚合中使用
  • 尝试将group_by: request.id 添加到query
  • 还是不行。现在它对另一列也说了同样的话。具体来说:** (Postgrex.Error) ERROR 42803 (grouping_error): column "v2.id" 必须出现在 GROUP BY 子句中或在聚合函数中使用

标签: mysql postgresql elixir phoenix-framework ecto


【解决方案1】:

在子查询中计算总和,并从主查询中加入:

q1 = from votes in Vote,
     group_by: votes.request_id,
     select: %{request_id: votes.request_id, total_rating: sum(votes.rating)}

q2 = from request in Request,
     left_join: song in assoc(request, :song),
     left_join: rating in subquery(q2), on: request.id == rating.request_id,
     where: request.zone_id == ^zone_id and request.times_played <= ^max_played,
     select: %{title: song.title, url: song.url, thumbnail: song.thumbnail, rating: rating.total_rating},
     order_by:  [asc: request.times_played, desc: request.inserted_at]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多