0

假设有一个名为“活动”的表,其中包含以下列:

whenItHappened 日期时间,谁发短信,什么短信

我想选择最近一小时内 10 个最近活跃用户的 5 个最近操作。

到目前为止,我有:

SELECT * FROM activity
JOIN (
    SELECT who FROM activity
    WHERE whenItHappened >= (CURDATE()- INTERVAL 1 HOUR)
    GROUP BY (who)
    ORDER BY whenItHappened DESC
    LIMIT 10
) AS unique_recent_users
ON unique_recent_users.who = activity.who;

这可以很好地选择最后十个最近活跃用户的所有活动。但是,我想不出一个好的方法来将其限制为每个用户的最后五个操作。

如果我在 SQL 语句的末尾放置一个 LIMIT 子句,它总共只会返回五个结果。期望的行为是,如果在过去一小时内有 10 个活跃用户,它应该显示 50 个操作,每个最近活跃的用户有 5 个操作。

我可以通过使用 PHP 对一个查询轻松地做到这一点,以获取最近的 10 个用户,然后每个用户执行 5 个操作,但我不禁想到必须有一些优雅的方式在 MySQL 中本地执行此操作。

编辑:(通过 Darrrrren 的链接,我找到了这个解决方案,它允许我从所有用户中选择 5 个最近的操作。我不确定随着表变大,性能会如何。)

select whenItHappened, who, what
from activity
where (
   select count(*) from activity as a
   where a.who = activity.who and a.whenItHappened <= activity.whenItHappened
) <= 5;
4

1 回答 1

0

在 MySQL 中没有办法优雅地做到这一点。一种有效的方法需要自联接:

select a.*
from (SELECT who
      FROM activity
      WHERE whenItHappened >= (CURDATE()- INTERVAL 1 HOUR)
      GROUP BY (who)
      ORDER BY whenItHappened DESC
      LIMIT 10
     ) AS unique_recent_users join
     Activity a
     on unique_recent_users.who = activity.who join
     Activity a2
     on a2.who = a.who and
        a2.whenItHappened >= a.WhenItHappened
group by a.id
having count(*) <= 5

(请注意,这是使用 MySQL 的隐藏列“功能”来返回group by语句中未包含的列。)

如果您碰巧在每个用户的活动表中有一个计数器,那么您可以使用此计数器来获取最近的五个。如果您想要 50 个最近的活动,无论用户如何,您也可以这样做。而且,如果您使用几乎任何其他数据库,那么排名函数(row_number()特别是)将优雅地解决问题。

于 2012-11-09T20:10:47.773 回答