给定以下模型:
User
id
UserPulses
id, user_id, group_id, created_at
我想做的是获取按(group_id)分组的所有用户的UserPulse,并且只获取每个group_id 的最新UserPulse。我已经能够通过逐组循环来做到这一点,但这需要大量查询。这可以通过一个查询来实现吗?
类似于:user.user_pulses.group("group_id)")
有任何想法吗?谢谢
给定以下模型:
User
id
UserPulses
id, user_id, group_id, created_at
我想做的是获取按(group_id)分组的所有用户的UserPulse,并且只获取每个group_id 的最新UserPulse。我已经能够通过逐组循环来做到这一点,但这需要大量查询。这可以通过一个查询来实现吗?
类似于:user.user_pulses.group("group_id)")
有任何想法吗?谢谢
您不能通过通常的 ActiveRecord 接口可靠地执行此操作,但您可以使用窗口函数通过 SQL 执行此操作。你想要一些这样的 SQL:
select id, user_id, group_id, created_at
from (
select id, user_id, group_id, created_at,
row_number() over (partition by group_id order by created_at desc, id desc) as r
from user_pulses
where user_id = :user_id
) dt
where r = 1
然后将其包装在find_by_sql
:
pulses = UserPulses.find_by_sql([%q{
select id, user_id, group_id, created_at
from (
select id, user_id, group_id, created_at,
row_number() over (partition by group_id order by created_at desc, id desc) as r
from user_pulses
where user_id = :user_id
) dt
where r = 1
}, :user_id => user.id])
窗口函数部分本质上对每个 GROUP BY 执行本地 GROUP BY ,对group_id
它们进行排序(id desc
作为辅助排序键作为“以防万一”的决胜局),并将每组的行号添加到r
. 然后外部查询过滤掉每个组 ( where r = 1
) and peels off the original
user_pulses 列中的第一个。
您可以使用 SQL 特性的 PostgreSQL 特定扩展DISTINCT
:DISTINCT ON
SELECT DISTINCT ON (group_id)
id, user_id, group_id, created_at
FROM user_pulses
WHERE user_id = :user_id
ORDER BY group_id, created_at DESC, id; -- id just to break ties
比窗口函数更简单(但不那么便携)并且可能最快。此相关问题下的
更多详细信息。
可能是这样的。但是,如果用户/组 ID 组合的日期相同,则它们可能有多个记录。
SELECT p.id, p.user_id, p.group_id, p.created_at
FROM UserPulses p
,( SELECT user_id, group_id, MAX(created_at) as max_date
FROM UserPulses
GROUP BY user_id, group_id ) m
WHERE u.user_id = m.user_id
AND u.group_id = m.group_id
AND u.created_at = m.max_date