0

我需要为每个符合一系列条件的用户返回表中的最新 2 行。

例如,“从产品表中获取最新的 2 行,其中用户的用户状态不是待处理,并且用户注册时间超过一周”。

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

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

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

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

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

4

2 回答 2

3

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

SELECT * FROM `products` p1
WHERE (SELECT COUNT(*) 
    FROM `products` p2 
    WHERE p2.added > p1.added
      AND p2.owner_id = p1.owner_id
    ) < 2
于 2013-10-31T19:03:46.640 回答
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_id和对结果进行排序date
  • 它声明了两个变量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。

这是有点放克的代码,但如果您为andCOUNT(*)创建索引,它的性能应该比对应的更好。OWNER_IDADDED

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


工作小提琴

于 2013-10-31T20:05:11.557 回答