如何按DESC顺序分组

时间:2013-03-13 15:59:45

标签: php mysql sql database group-by

我有下表称为问题:

ID | asker 
1  | Bob
2  | Bob
3  | Marley

我只想选择每个提问者一次,如果有多个具有相同名称的问题,请选择最高ID之一。所以,预期结果:

ID | asker 
3  | Marley
2  | Bob

我使用以下查询:

SELECT * FROM questions GROUP by questions.asker ORDER by questions.id DESC

我得到以下结果:

ID | asker 
3  | Marley
1  | Bob

因此它会选择遇到的第一个'Bob'而不是最后一个。

由于

7 个答案:

答案 0 :(得分:40)

如果您想要每个id的最后asker,那么您应该使用聚合函数:

SELECT max(id) as id, 
   asker
FROM questions 
GROUP by asker 
ORDER by id DESC

您获得异常结果的原因是因为MySQL使用了GROUP BY的扩展,它允许选择列表中的项目是非聚合的,并且不包含在GROUP BY子句中。但是这会导致意外的结果,因为MySQL可以选择返回的值。 (见MySQL Extensions to GROUP BY

来自MySQL文档:

  

MySQL扩展了GROUP BY的使用,因此选择列表可以引用GROUP BY子句中未命名的非聚合列。 ...您可以通过避免不必要的列排序和分组来使用此功能来获得更好的性能。但是,当GROUP BY中未命名的每个非聚合列中的所有值对于每个组都相同时,这非常有用。服务器可以自由选择每个组中的任何值,因此除非它们相同,否则所选的值是不确定的。此外,添加ORDER BY子句不会影响每个组中值的选择。选择值后会对结果集进行排序,而ORDER BY不会影响服务器选择的值。

现在,如果您需要从表中返回其他列,但由于结果不一致而不希望将它们添加到GROUP BY,那么您可以使用子查询这样做。 (Demo

select 
  q.Id,
  q.asker,
  q.other -- add other columns here
from questions q
inner join
(
  -- get your values from the group by
  SELECT max(id) as id, 
    asker
  FROM questions 
  GROUP by asker 
) m
  on q.id = m.id
order by q.id desc

答案 1 :(得分:18)

通常,MySQL只允许按升序记录进行分组。所以我们可以在分组之前订购记录。

SELECT *
FROM (
  SELECT *
  FROM questions
  ORDER BY id DESC
) AS questions
GROUP BY questions.asker

答案 2 :(得分:3)

需要使用GROUP BYMAX()对记录进行分组,以获取每个asker的最大ID。

SELECT  asker, MAX(ID) ID
FROM    TableName
GROUP   BY asker

输出

╔════════╦════╗
║ ASKER  ║ ID ║
╠════════╬════╣
║ Bob    ║  2 ║
║ Marley ║  3 ║
╚════════╩════╝

答案 3 :(得分:2)

其他人使用MAX(ID)获得您想要的结果是正确的。如果您想知道为什么您的查询不起作用,那是因为ORDER BY在<{em> GROUP BY之后发生了

答案 4 :(得分:0)

获取每一栏:

SELECT * FROM questions
WHERE id IN 
(SELECT max(id) as id, asker
FROM questions 
GROUP by asker 
ORDER by id DESC)

改进了@bluefeet答案的版本。

答案 5 :(得分:0)

我写这个答案是因为@Taryn在公认答案中的第一个/较短的替代方法只有在您只选择了GROUP BY和MAX中使用的列时才起作用。用户提出的问题是选择表中的所有列(他使用了SELECT *)。因此,当您向表中添加另一个第三列时,查询结果中的该列值将不正确。您将从不同的表行中获得混合值。 @Taryn的第二个/更长的替代方法(使用内部联接和子查询)可以工作,但是查询毫无用处,并且在我的用例中,速度慢了5倍,比我下面的简单替代方法慢。


考虑表questions

id | asker 
-----------
1  | Bob
2  | Bob
3  | Marley

查询SELECT max(id) as id, asker FROM questions GROUP BY asker ORDER BY id DESC返回期望

id | asker 
-----------
3  | Marley
2  | Bob

现在考虑另一个表questions

id | asker  | other
-------------------
1  | Bob    | 1st
2  | Bob    | 2nd
3  | Marley | 3rd

查询SELECT max(id) as id, asker, other FROM questions GROUP BY asker ORDER BY id DESC返回意外

id | asker  | other
-------------------
3  | Marley | 3rd
2  | Bob    | 1st

...请注意,结果第二行的other值不正确,因为id=2来自表的第二行,而other=1st来自表的第一行!这样一来,许多用户在评论Taryn的答案报告时都认为此解决方案无效。


同时选择另一列时,可能的简单解决方案是使用GROUP BY + DESC

SELECT id, asker, other FROM questions GROUP BY asker DESC

id | asker  | other
-------------------
3  | Marley | 3rd
2  | Bob    | 2nd

(请参见演示:https://www.db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/10

...但是这种简单的解决方案有一些局限性:

  • 表必须是InnoDB(我认为这不是问题,因为您会获得更好的性能,而且因为MySQL> = 5.5.5默认/首选存储引擎已从MyISAM更改为InnoDB)
  • 您必须为GROUP BY中使用的列创建索引-因此,在这种情况下,asker(我认为这不是问题,因为由于索引适用于这种情况,您将获得更好的性能。GROUP BY通常需要创建tmp表,但是当索引可用时将不会创建tmp表,这会更快)
  • 对于MySQL 5.7和8.0,需要禁用SQL模式ONLY_FULL_GROUP_BY(例如SET SESSION sql_mode = '';)或在未汇总的选定列上使用ANY_VALUE()以避免错误ER_WRONG_FIELD_WITH_GROUP。
  • 不幸的是,自MySQL 8.0 https://dev.mysql.com/worklog/task/?id=8693起,MySQL开发人员通过GROUP BY删除了对ASC / DESC的支持,但幸运的是,还有替代方法GROUP BY col1 ORDER BY col1 ASC/DESC

SELECT id, asker, other FROM questions GROUP BY asker ORDER BY asker DESC

id | asker  | other
-------------------
3  | Marley | 3rd
2  | Bob    | 2nd

(请参见演示:https://www.db-fiddle.com/f/esww483qFQXbXzJmkHZ8VT/11

...结果与上述GROUP BY ... DESC相同(请不要忘记使用InnoDB并创建索引)。

答案 6 :(得分:0)

这是因为ORDER BY是在之后 GROUP BY执行的。

尝试一下:

SELECT * FROM questions
WHERE id IN 
(
    SELECT max(id) as id
    FROM questions 
    GROUP by asker 
    ORDER by id DESC
)