我有下表称为问题:
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'而不是最后一个。
由于
答案 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 BY
和MAX()
对记录进行分组,以获取每个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)
...但是这种简单的解决方案有一些局限性:
asker
(我认为这不是问题,因为由于索引适用于这种情况,您将获得更好的性能。GROUP BY通常需要创建tmp表,但是当索引可用时将不会创建tmp表,这会更快)SET SESSION sql_mode = '';
)或在未汇总的选定列上使用ANY_VALUE()
以避免错误ER_WRONG_FIELD_WITH_GROUP。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
)