【问题标题】:MySQL fetch total 20 rows but only 10 rows of each unique idMySQL 获取总共 20 行,但每个唯一 ID 仅 10 行
【发布时间】:2014-05-07 12:31:03
【问题描述】:

我在这里有一个小问题,我会试着解释一下。我想获取表中每个唯一 id 的最新(最高 id)最多 10 行(可以多于/少于 10 行)。

因此,如果我有兴趣了解 id "1" 和 "2" 中的最新 10 行,我会将 LIMIT 设置为 20 (2 * 10)。

这就是我当前的查询现在的样子(它会错误地获取第一个 id 的最新 20 行,因为该 id 存在超过 10 行)。

SELECT positions.id
     , trackedpersons.name
     , trackedpersons.id
     , events.name
     , events.route
     , positions.latitude
     , positions.longitude
     , positions.datetime 
  FROM trackedpersons
     , positions
     , events 
 WHERE trackedpersons.id IN (1,2) 
   AND events.id = 1 
   AND events.id = positions.eventid 
   AND positions.trackedpersonid = trackedpersons.id 
 ORDER 
    BY trackedpersons.id
     , positions.id DESC 
 LIMIT 20;

【问题讨论】:

  • 不要使用隐式(逗号)连接语法。相反,始终使用显式 JOIN 语法。除此之外,这是一个 Top-N 问题(每天都会被问到和回答的那种)
  • @Strawberry 我主要使用隐式连接,有什么区别?
  • 我也想知道:)
  • MySQL 以不同的顺序评估连接,具体取决于它们是隐式的还是显式的。如果它们都是隐式的,这无关紧要(与 2*3*6 = 6*2*3 相同),但是当与 OUTER JOIN(不能隐式表达)结合使用时,您将开始得到错误或意外结果。另外,它更难阅读。
  • @flaschenpost 这是评论,不是答案。

标签: mysql top-n


【解决方案1】:

很好;这是一种方法 - 虽然它不是最有效的......

考虑以下...

DROP TABLE IF EXISTS my_table;

CREATE TABLE my_table 
(id INT NOT NULL
,dt INT NOT NULL
,PRIMARY KEY(id,dt)
);

INSERT INTO my_table VALUES
(101,1),
(101,2),
(101,3),
(101,4),
(102,1),
(102,2),
(102,3),
(102,4),
(102,5),
(103,1),
(103,2),
(103,3),
(104,1),
(104,2),
(105,1);

SELECT * FROM my_table;
+-----+----+
| id  | dt |
+-----+----+
| 101 |  1 |
| 101 |  2 |
| 101 |  3 |
| 101 |  4 |
| 102 |  1 |
| 102 |  2 |
| 102 |  3 |
| 102 |  4 |
| 102 |  5 |
| 103 |  1 |
| 103 |  2 |
| 103 |  3 |
| 104 |  1 |
| 104 |  2 |
| 105 |  1 |
+-----+----+

要发现每行在其组中的位置(排名),我们可以这样做...

SELECT x.*
     , COUNT(*) rank 
  FROM my_table x 
  JOIN my_table y 
    ON y.id = x.id 
   AND y.dt >= x.dt 
 GROUP 
    BY x.id,x.dt 
 ORDER 
    BY id
     , rank;
+-----+----+------+
| id  | dt | rank |
+-----+----+------+
| 101 |  4 |    1 |
| 101 |  3 |    2 |
| 101 |  2 |    3 |
| 101 |  1 |    4 |
| 102 |  5 |    1 |
| 102 |  4 |    2 |
| 102 |  3 |    3 |
| 102 |  2 |    4 |
| 102 |  1 |    5 |
| 103 |  3 |    1 |
| 103 |  2 |    2 |
| 103 |  1 |    3 |
| 104 |  2 |    1 |
| 104 |  1 |    2 |
| 105 |  1 |    1 |
+-----+----+------+

...可以这样重写(从每个id中获取前3个)...

SELECT x.*  
  FROM my_table x 
  JOIN my_table y  
    ON y.id = x.id 
   AND y.dt >= x.dt 
 GROUP 
    BY x.id
     , x.dt 
HAVING COUNT(*) <= 3;
+-----+----+
| id  | dt |
+-----+----+
| 101 |  2 |
| 101 |  3 |
| 101 |  4 |
| 102 |  3 |
| 102 |  4 |
| 102 |  5 |
| 103 |  1 |
| 103 |  2 |
| 103 |  3 |
| 104 |  1 |
| 104 |  2 |
| 105 |  1 |
+-----+----+

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-30
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多