9

我有一个 MySQL 数据库(博客),它有一个 id、title、timestamp 和 category_id 列名。如何从具有最新时间戳的每个类别中选择一行?如果我有 3 行属于类别 1、2、1,那么我将返回两行,其中“1”中类别的最高时间戳作为第一行,类别“2”的行作为第二行。

我试过了:

SELECT title, timestamp, category_id
FROM blogs 
WHERE timestamp IN (
  SELECT MAX(timestamp) 
  FROM blogs 
  GROUP BY category_id
)

但是由于时间戳不是唯一的,因此可以说,它可以拉入一个带有 category_id = 1 的额外行,该行与在内部选择语句中选择的 category_id = 2 的行具有相同的时间戳。

4

2 回答 2

10

对于 MySQL,此查询将返回您指定的结果集:

SELECT b.title
     , MAX(b.timestamp)
     , b.category_id
  FROM blogs b
 GROUP BY b.category_id

如果在具有相同最新“时间戳”的类别中碰巧有多个“标题”,则只会返回该类别的一行,因此每个类别只会返回一个“标题”。


注意:其他 DBMS 系统将抛出与上述查询类似的异常(错误),因为 SELECT 列表中未出现在 GROUP BY 中的非聚合的处理。

您的查询非常接近。您已经获得了返回每个类别的“最新”时间戳的内部查询。下一步是返回 category_id 以及最新的时间戳。

SELECT category_id, MAX(timestamp) AS timestamp
  FROM blogs
 GROUP BY category_id

下一步是将其加入到 中blogs,以获取关联的“标题”

SELECT b.title
     , b.timestamp
     , b.category_id
  FROM (SELECT category_id, MAX(timestamp) AS timestamp
          FROM blogs 
         GROUP BY category_id
       ) l
  JOIN blogs b
    ON b.category_id = l.category_id AND b.timestamp = l.timestamp 

注意:如果一个类别有多个“最新”行(时间戳值匹配),则此查询将返回它们。

如果这是一个问题,可以修改查询(或以不同的方式编写)以防止一个类别出现两行的任何可能性。


只需向该查询添加一个 GROUP BY 子句即可(仅在 MySQL 中,而不是在其他 DBMS 中)

SELECT b.title
     , b.timestamp
     , b.category_id
  FROM (SELECT category_id, MAX(timestamp) AS timestamp
          FROM blogs 
         GROUP BY category_id
       ) l
  JOIN blogs b
    ON b.category_id = l.category_id AND b.timestamp = l.timestamp
 GROUP BY b.timestamp, b.category_id

(对于其他 DBMS,您可以修改 SELECT 列表,替换b.titleMAX(b.title) AS title。当您从行中返回单个列时,这将起作用。

如果您希望以特定顺序返回行,请添加 ORDER BY 子句。


于 2012-08-02T18:04:47.553 回答
0

你也可以试试这个方法。当我在 MYSQL 5.6 中尝试时为我工作。它返回具有最高时间戳和 category_id 升序的两个类别。

SELECT title , timestamp , category_id FROM blogs WHERE timestamp in (select max(timestamp) from blogs group by category_id) group by timestamp,category_id order by category_id asc;

于 2016-03-16T16:47:05.897 回答