在Rails中使用Postgres限制SQL结果

3
我有一个应用程序,其中包含音乐排行榜以展示热门曲目(显示前十名)。
然而,我想限制排行榜,使得任何特定用户不能同时拥有超过2首歌曲在排行榜上。如果艺术家A通常会有排行榜中的4个前十名位置,那么只会显示艺术家A的前两首热门曲目(假设它们当然不是由艺术家A创作的)。此时,列表中的第11和第12项将各上升2个位置。
所以,假设这是当前的热门曲目部分:
  1. 艺术家A的歌曲A
  2. 艺术家B的歌曲B
  3. 艺术家A的歌曲C
  4. 艺术家C的歌曲D
  5. 艺术家D的歌曲E
  6. 艺术家E的歌曲F
  7. 艺术家F的歌曲G
  8. 艺术家A的歌曲H
  9. 艺术家A的歌曲I
  10. 艺术家G的歌曲J
我想限制SQL查询结果,使得#8和#9不包括在内(因为查询结果中只允许每个艺术家最多有2首热门曲目),列表将变成:
  1. 艺术家A的歌曲A
  2. 艺术家B的歌曲B
  3. 艺术家A的歌曲C
  4. 艺术家C的歌曲D
  5. 艺术家D的歌曲E
  6. 艺术家E的歌曲F
  7. 艺术家F的歌曲G
  8. 艺术家G的歌曲J
  9. 艺术家H的歌曲K(之前是#11)
  10. 艺术家I的歌曲L(之前是#12)
顺便说一下,我正在使用Postgres,这是我现在拥有的。它计算最近14天内每个曲目的播放次数以生成前10名列表。我想修改它以获得上述所需的限制。
def self.top_tracks_past14(max=3)
  Track.find_by_sql(["select COALESCE(sum(plays.clicks), 0), tracks.*
    from tracks
    left join plays
    on tracks.id = plays.track_id
    and plays.created_at > now() - interval '14 days'
    inner join albums
    on tracks.album_id = albums.id
    inner join users
    on albums.user_id = users.id
    group by tracks.id
    order by 1 desc limit ?", max])
end
1个回答

1
select trackid, userid, totalclicks from 
(
select *, 
row_number() over(partition by userid order by totalclicks desc) as rn
from
 (
select COALESCE(sum(plays.clicks), 0) as totalclicks,plays.track_id as trackid,
users.id as userid
from tracks
left join plays
on tracks.id = plays.track_id
and plays.created_at > now() - interval '14 days'
inner join albums
on tracks.album_id = albums.id
inner join users
on albums.user_id = users.id
group by plays.track_id, users.id
  ) t
) t1
where t1.rn <= 2
order by 1 desc
limit 10; 

你可以使用row_number函数,在顶部曲目中每个用户仅选择2行。
编辑:根据OP的要求,来自tracks、albums、users、plays的所有列将在外部查询中可用。如果您需要从这些表中排除计算得出的rn,请确保从这些表中选择所需的列。
def self.top_tracks_past14(max=3)
Track.find_by_sql(["select t1.trackid, t1.userid, t1.totalclicks from 
(
select t.trackid, t.userid, t.totalclicks, 
row_number() over(partition by t.userid order by t.totalclicks desc) as rn
from
 (
select COALESCE(sum(plays.clicks), 0) as totalclicks,plays.track_id as trackid
,users.id as userid
from tracks
left join plays
on tracks.id = plays.track_id
and plays.created_at > now() - interval '14 days'
inner join albums
on tracks.album_id = albums.id
inner join users
on albums.user_id = users.id
group by plays.track_id, users.id
  ) t
) t1
where t1.rn <= 2
order by t1.totalclicks desc limit ?", max])
end

嘿@vkp,谢谢你的建议。我遇到了一个错误(“参数错误(0个而需要1..2个)”)。你能否把你的答案与我的“def self.top_tracks_past14…”语法结合起来,以便消除我这边可能存在的任何问题/困惑? - Andrew
@Andrew,我修改了你的函数以包含查询。由于我不确定Ruby,所以请告诉我它的运行情况。 - Vamsi Prabhala
你修改后的代码出现了一个新的错误,可以通过删除“tracks.*”后面的逗号来修复。然而,它似乎没有返回最近14天内播放次数最多的10首歌曲(每位艺术家最多2首)。相反,它似乎是按照id顺序返回的10首歌曲(从1到10)。 - Andrew
这个fiddle展示了查询背后的逻辑http://sqlfiddle.com/#!15/06991/7 .. 你能否请发布你得到的结果以及表中的数据? - Vamsi Prabhala
如果您能在Fiddle中创建表并尝试一下,然后再发布链接,那就太好了。 - Vamsi Prabhala
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接