每个用户返回2行

时间:2013-10-31 18:56:26

标签: mysql sql

我需要在表格中为每个符合一系列标准的用户返回最新的2行。

例如,“从产品表中获取最新的2行,用户状态未挂起的用户,并且用户注册的时间超过一周”。

我不完全确定从哪里开始。如果每个用户只有一行就很简单。同样,如果我可以将结果转储出来并在我的PHP代码中进行进一步过滤,我可以通过这种方式使其工作(但是我需要LIMIT分页,所以它需要全部在查询中)。

我已经设置了一个非常简化的表格,其中包含一些数据,只是为了便于处理,您可以在此处看到:

http://sqlfiddle.com/#!2/b32d2

基本上,解决方案查询每个“owner_id”最多返回两行,返回的两行将是“添加”列中最高的2个日期。

希望这是有道理的,并感谢任何可以提供帮助的人。

2 个答案:

答案 0 :(得分:3)

这是非常低效的,但它确实有效。

SELECT * FROM `products` p1
WHERE (SELECT COUNT(*) 
    FROM `products` p2 
    WHERE p2.added > p1.added
      AND p2.owner_id = p1.owner_id
    ) < 2

答案 1 :(得分:0)

SELECT *
FROM
(
  SELECT 
   P2.ID,
   IF (@PREVIOUS_OWNER = P2.OWNER_ID, 
     @CURRANK := @CURRANK + 1, 
     @CURRANK := 1) AS RANK,
   (@PREVIOUS_OWNER := P2.OWNER_ID) AS OWNER_ID,
   P2.ADDED
  FROM PRODUCTS P2, (SELECT @CURRANK := -1, @PREVIOUS_OWNER := -1) R
  ORDER BY P2.OWNER_ID, P2.ADDED DESC
  ) P
WHERE P.RANK <= 2

这个查询在做什么?

  • 根据owner_iddate
  • 对结果进行排序
  • 它声明了两个变量CURRANKPREVIOUS_OWNER
  • PREVIOUS_OWNER将在计算 OWNER_ID之后评估为当前CURRANK ,这意味着IF语句PREVIOUS_OWNER对于第一行, -1 ,对于每隔一行,上一行 OWNER_ID
  • 最后但并非最不重要的是,如果PREVIOUS_OWNER与当前OWNER_ID相同,那么我们会增加CURRANK,否则我们会将其重置为1(if子句),以便我们可以模拟按OWNER_ID
  • 分区

因此内部查询将根据ADDED对来自同一所有者的每个产品进行排名。排名别名为RANK

外部查询过滤RANK小于或等于2.

这是一种有趣的代码,但如果为COUNT(*)OWNER_ID创建索引,则可能会比ADDED代码更好。

无论如何,我们正在推动MySQL应该做的事情的边缘,并创建一个潜在巨大的内存表(P),以便每OWNER_ID提取几行,所以这不是美丽也不推荐。尽管如此,据我所知,在MySQL开始支持子查询中的分析函数或LIMIT子句之前,这是一样好的。


Working fiddle