限制从内部联接返回的行数

时间:2013-04-19 03:18:36

标签: mysql greatest-n-per-group

我有两张桌子,车辆的描述和一个lat / long的非理想表格。两个表都有一个Id键(PK和FK)。

我的SELECT看起来像这样

SELECT vehicles.id,          vehicles.description, vehicles.type, 
       positions.time_stamp, positions.latitude,   positions.longitude

       FROM         vehicles
       INNER JOIN   positions 
       ON           vehicles.id=positions.id

我想订购并限制它,以便它只显示每辆车报告的最新poisiotn的连接值。

我该怎么做?感谢


[更新]我创建了this SqlFiddle demo,但未提供所需的结果。

我认为我需要的是

   ORDER BY     positions.time_stamp DESC
   LIMIT SELECT COUNT(*) FROM vehicles

如果只是有效的语法: - /


[进一步更新]适用于那些关注thinsg执行顺序的人:

  1. positions表中没有删除,只有插入
  2. 每辆车每隔几分钟插入一次
  3. 我可以忍受奇怪的异常昙花一现,我感到非常罕见
  4. 车辆的细节不太可能改变,我正在做的是增加新的位置
  5. 这会让事情变得更容易吗?

5 个答案:

答案 0 :(得分:6)

如果(id, time_stamp)是唯一的,即同一车辆和同一time_stamp没有两行,您可以使用内联视图(mysql将其称为派生表)来获取每辆车的最新time_stamp。然后,您可以将该派生表连接到位置表,以获取其他列,如下所示:

SELECT v.id
     , v.description
     , v.type
     , p.time_stamp
     , p.latitude
     , p.longitude
  FROM ( SELECT MAX(l.time_stamp) AS max_time_stamp
              , l.id
           FROM positions l
          GROUP BY l.id
       ) m
 JOIN positions p
    ON p.id = m.id
   AND p.time_stamp = m.max_time_stamp
  JOIN vehicles v
    ON v.id = p.id

您可以在内联视图中运行该查询(在上面的查询中分配了m的别名,以验证这是否为每辆车返回最新的time_stamp。

如果您希望按特定顺序排列结果,可以添加ORDER BY。 (此查询有可能为车辆返回多行,IFF最新的time_stamp值出现在同一车辆的两个(或更多)行上。如果没有为车辆复制time_stamp值,则不会发生这种情况。)

适当的索引将加速派生表的创建,并加速连接操作回到位置表:

 CREATE INDEX positions_IX1 ON positions (id,time_stamp)

(在其他关系数据库中,例如Oracle和SQL Server,我们可以使用“分析函数”,但MySQL尚不支持这些类型的函数。)

答案 1 :(得分:1)

SELECT v.id, v.description, v.type, p.time_stamp, p.latitude, p.longitude
FROM vehicles v
INNER JOIN positions p ON v.id = p.id
GROUP BY v.id
ORDER BY p.time_stamp DESC

答案 2 :(得分:1)

SELECT v.id, v.description, v.type,
       cur_pos.time_stamp, cur_pos.latitude, cur_pos.longitude
FROM vehicles AS v,
(
    SELECT p.time_stamp, p.latitude, p.longitude
    FROM positions AS p
    WHERE p.id = v.id
    ORDER BY p.time_stamp DESC
    LIMIT 1
) AS cur_pos

还有其他方法可以做到这一点;以下是一次尝试,但正如下面的评论所指出的那样,它并没有像原来的海报那样做。我保留它仅供参考:

SELECT v.id, v.description, v.type,
       MAX(p.time_stamp), p.latitude, p.longitude
FROM vehicles AS v INNER JOIN positions AS p ON v.id = p.id
GROUP BY v.id, v.description, v.type, p.latitude, p.longitude

答案 3 :(得分:1)

查询:

<强> SQLFIDDLEExample

SELECT v.id
     , v.description
     , v.type
     , p.time_stamp
     , p.latitude
     , p.longitude
  FROM positions p
  JOIN vehicles v ON v.id = p.id
WHERE p.time_stamp = (SELECT MAX(l.time_stamp)
                      FROM positions l
                      WHERE l.id = p.id)

结果:

| ID | DESCRIPTION | TYPE |                   TIME_STAMP | LATITUDE | LONGITUDE |
---------------------------------------------------------------------------------
|  1 |     Trabant |  car | April, 19 2013 13:43:12+0000 | 26.77994 | 402.46261 |
|  2 |    Bus # 42 |  bus | April, 19 2013 13:43:12+0000 | 32.77994 |  48.46261 |

答案 4 :(得分:0)

尝试此查询 -

SELECT
  v.id, v.description, v.type, t.id, t.time_stamp, t.latitude, t.longitude
FROM vehicles v
  JOIN (
    SELECT t1.*, COUNT(*) num FROM positions t1
      LEFT JOIN positions t2
        ON t2.id = t1.id AND t2.time_stamp >= t1.time_stamp
    GROUP BY
      t1.id, t1.time_stamp
    ) t
  ON v.id = t.id
WHERE
  num <= 2;

+----+-------------+------+----+---------------------+-----------+-----------+
| id | description | type | id | time_stamp          | latitude  | longitude |
+----+-------------+------+----+---------------------+-----------+-----------+
|  1 | Trabant     | car  |  1 | 2013-04-25 09:45:39 | 161.77994 | 102.46261 |
|  1 | Trabant     | car  |  1 | 2013-04-25 09:45:40 | 261.77994 | 402.46261 |
|  2 | Bus # 42    | bus  |  2 | 2013-04-25 09:45:39 | 221.77994 |  88.46261 |
|  2 | Bus # 42    | bus  |  2 | 2013-04-25 09:45:40 | 321.77994 |  48.46261 |
+----+-------------+------+----+---------------------+-----------+-----------+

更改最后一行中的num值,以选择每组所需的输出记录数。给定的示例每组输出2条记录。