11

我的桌子titles看起来像这样

id |group|date                |title
---+-----+--------------------+--------
1  |1    |2012-07-26 18:59:30 | Title 1
2  |1    |2012-07-26 19:01:20 | Title 2
3  |2    |2012-07-26 19:18:15 | Title 3
4  |2    |2012-07-26 20:09:28 | Title 4
5  |2    |2012-07-26 23:59:52 | Title 5

我需要按日期降序排列的每个组的最新结果。像这样的东西

id |group|date                |title
---+-----+--------------------+--------
5  |2    |2012-07-26 23:59:52 | Title 5
2  |1    |2012-07-26 19:01:20 | Title 2

我试过

SELECT *
FROM `titles`
GROUP BY `group`
ORDER BY MAX( `date` ) DESC

但我从小组中得到了第一个结果。像这样

id |group|date                |title
---+-----+--------------------+--------
3  |2    |2012-07-26 18:59:30 | Title 3
1  |1    |2012-07-26 19:18:15 | Title 1

我究竟做错了什么?如果我使用 LEFT JOIN,这个查询会更复杂吗?

4

8 回答 8

11

这个页面对我很有帮助;它教会了我如何使用自联接来获得每组的最大/最小/某事-n 行。

在您的情况下,它可以应用于您想要的效果,如下所示:

SELECT * FROM
(SELECT group, MAX(date) AS date FROM titles GROUP BY group)
AS x JOIN titles USING (group, date);
于 2012-07-27T21:29:25.290 回答
1

我通过谷歌找到了这个主题,看起来我遇到了同样的问题。如果像我一样不喜欢子查询,这是我自己的解决方案:

-- Create a temporary table like the output
CREATE TEMPORARY TABLE titles_tmp LIKE titles;

-- Add a unique key on where you want to GROUP BY
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`);

-- Read the result into the tmp_table. Duplicates won't be inserted.
INSERT IGNORE INTO titles_tmp
  SELECT *
    FROM `titles`
    ORDER BY  `date` DESC;

-- Read the temporary table as output
SELECT * 
  FROM titles_tmp
  ORDER BY `group`;

它有更好的性能。如果 date_column 与 auto_increment_one 具有相同的顺序,以下是提高速度的方法(然后您不需要 ORDER BY 语句):

-- Create a temporary table like the output
CREATE TEMPORARY TABLE titles_tmp LIKE titles;

-- Add a unique key on where you want to GROUP BY
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`);

-- Read the result into the tmp_table, in the natural order. Duplicates will update the temporary table with the freshest information.
INSERT INTO titles_tmp
  SELECT *
    FROM `titles`

  ON DUPLICATE KEY 
    UPDATE  `id`    = VALUES(`id`), 
            `date`  = VALUES(`date`), 
            `title` = VALUES(`title`);

-- Read the temporary table as output
SELECT * 
  FROM titles_tmp
  ORDER BY `group`;

结果 :

+----+-------+---------------------+---------+
| id | group | date                | title   |
+----+-------+---------------------+---------+
|  2 |     1 | 2012-07-26 19:01:20 | Title 2 |
|  5 |     2 | 2012-07-26 23:59:52 | Title 5 |
+----+-------+---------------------+---------+

在大型表上,此方法在性能方面具有重要意义。

于 2015-06-10T11:21:08.283 回答
0

好吧,如果日期在组中是唯一的,这将起作用(如果不是,您将看到与组中的最大日期匹配的几行)。(此外,列的错误命名、“组”、“日期”可能会给您带来语法错误,尤其是“组”)

select t1.* from titles t1, (select group, max(date) date from titles group by group) t2
where t2.date = t1.date
and t1.group = t2.group
order by date desc
于 2012-07-27T21:29:54.750 回答
0

另一种方法是利用 MySQL 用户变量来识别group值中的“控制中断”。

如果您可以忍受返回的额外列,则可以使用以下方法:

SELECT IF(s.group = @prev_group,0,1) AS latest_in_group
     , s.id
     , @prev_group := s.group AS `group`
     , s.date
     , s.title
  FROM (SELECT t.id,t.group,t.date,t.title
          FROM titles t
         ORDER BY t.group DESC, t.date DESC, t.id DESC
       ) s
  JOIN (SELECT @prev_group := NULL) p
HAVING latest_in_group = 1
 ORDER BY s.group DESC

这样做是groupdate降序排列所有行。(我们在 ORDER BY 中的所有列上指定 DESC,以防(group,date,id)MySQL 可以对其执行“反向扫描”的索引。id列的包含使我们获得确定性(可重复)行为,如果有多于一行具有最新date值。)那是别名为的内联视图s

我们使用的“技巧”是将值与前一行group的值进行比较。group每当我们有不同的值时,我们就知道我们正在开始一个“新”组,并且这一行是“最新”行(我们让 IF 函数返回 1)。否则(当组值匹配时),它不是最新的行(我们让 IF 函数返回 0)。

然后,我们过滤掉所有没有latest_in_group设置为 1 的行。

可以通过将该查询(作为内联视图)包装在另一个查询中来删除该额外的列:

SELECT r.id
     , r.group
     , r.date
     , r.title
  FROM ( SELECT IF(s.group = @prev_group,0,1) AS latest_in_group
              , s.id
              , @prev_group := s.group AS `group`
              , s.date
              , s.title
           FROM (SELECT t.id,t.group,t.date,t.title
                   FROM titles t
                  ORDER BY t.group DESC, t.date DESC, t.id DESC
                ) s
           JOIN (SELECT @prev_group := NULL) p
         HAVING latest_in_group = 1
       ) r
 ORDER BY r.group DESC
于 2012-07-27T21:53:20.867 回答
0

如果您的id字段是自动递增字段,并且可以肯定地说该id字段的最大值也是date任何组的最大值,那么这是一个简单的解决方案:

SELECT   b.*
FROM     (SELECT MAX(id) AS maxid FROM titles GROUP BY group) a
JOIN     titles b ON a.maxid = b.id
ORDER BY b.date DESC 
于 2012-07-27T21:55:25.030 回答
0

使用下面的 mysql 查询从表中获取最新的更新/插入记录。

SELECT * FROM 
(
  select * from `titles` order by `date` desc
) as tmp_table
group by `group`
order by `date` desc
于 2015-05-17T07:57:11.143 回答
0

使用以下查询从每个组中获取最新记录

SELECT 
T1.* FROM
(SELECT 
    MAX(ID) AS maxID
FROM
    T2
GROUP BY Type) AS aux
    INNER JOIN
T2 AS T2 ON T1.ID = aux.maxID ;

其中 ID 是您的自动增量字段,Type 是您想要分组的记录类型。

于 2016-07-13T10:43:55.343 回答
0

MySQL 使用了一个GROUP BY不可靠的哑扩展,如果你想得到这样的结果,你可以使用

select id, group, date, title from titles as t where id = 
(select id from titles where group = a.group order by date desc limit 1);

在此查询中,每次对每个组进行完整扫描时,它都可以找到最近的日期。我找不到任何更好的替代品。希望这会对某人有所帮助。

于 2017-06-15T08:00:23.030 回答