MySQL选择DISTINCT的一列,以及其他对应的列


192
ID   FirstName   LastName
1      John        Doe
2      Bugs        Bunny
3      John        Johnson

我想DISTINCTFirstName列中选择结果,但我需要相应的IDLastName

结果集只需要显示一个John,但必须显示ID1的a LastName和doe的a。


1
您想要姓氏属于最低ID且具有不同的名字吗?
Thomas Langston

3
选择头一个的逻辑是什么?我想您会希望John Doe和John Johnson都出现,因为他们是两个不同的Johns,但这就是我。
judda 2011年

4
DISTINCT不是功能。所有的答案DISTINCT()都是错误的。当您不放置该错误时,将显示该错误SELECT
问题溢出

1
ALL 在单词distinct之后使用括号的答案确实是错误的。Distinct不是函数,因此它不能接受参数。括号后面的括号仅被忽略。除非您使用的是PostgreSQL,括号中的括号将形成“复杂数据类型”
Used_By_Already

Answers:


191

试试这个查询

 SELECT ID, FirstName, LastName FROM table GROUP BY(FirstName)

15
我们如何知道将返回哪一行?
William Entriken

26
@Full Decent,根据MySQL 文档,您无法做到:“服务器可以从每个组中自由选择任何值,因此,除非它们相同,否则选择的值是不确定的。” 实际上,我已经在ORDER BY子句中成功使用了这种查询,例如,您可以添加ORDER BY id ASC / DESC,MySQL每次执行查询时都会返回一致的结果。但是我可以确定是否有人在生产环境中使用未记录的功能。
阿鲁纳斯Junevicius

2
OP没有提到mysql版本。
diEcho

2
@sinaza查看我针对MySQL 5.7.5+更改后的GROUP BY处理方式的
fyrye

3
这不适用于only_full_group_by模式,因为ID和LastName都不是聚合函数,也不是分组函数的一部分。救命!
ihodonald

63

DISTINCT关键字并未真正发挥你期待它的方式。使用SELECT DISTINCT col1, col2, col3时,实际上是在选择所有唯一的{col1,col2,col3}元组。


14
感谢您指出这一点,布莱恩。您能否提供一个示例,说明如何利用GROUP BY获得相同的结果?
先生

59

为了避免潜在的意想不到的结果时,使用GROUP BY不带聚合函数,作为公认的答案使用,因为MySQL是免费检索任何数据集内的值不使用聚合功能时被分组[原文]和问题进行ONLY_FULL_GROUP_BY。请考虑使用排除联接。

排除联接-明确实体

假设名字和姓氏被唯一索引(明确),则另一种选择GROUP BY是使用进行排序LEFT JOIN以过滤结果集,否则称为排除JOIN。

见示范

升序(AZ)

从AZ检索按姓氏排序的唯一姓氏

询问

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND t1.lastname > t2.lastname
WHERE t2.id IS NULL;

结果

| id | firstname | lastname |
|----|-----------|----------|
|  2 |      Bugs |    Bunny |
|  1 |      John |      Doe |

降序(ZA)

从ZA中检索按姓氏排序的唯一姓氏

询问

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND t1.lastname < t2.lastname
WHERE t2.id IS NULL;

结果

| id | firstname | lastname |
|----|-----------|----------|
|  2 |      Bugs |    Bunny |
|  3 |      John |  Johnson |

然后,您可以根据需要对结果数据进行排序。


排除联接-模棱两可的实体

如果名字和姓氏组合不是唯一的(模棱两可的),并且您有多行具有相同的值,则可以通过在JOIN条件上包括OR条件来过滤结果集,也可以按id进行过滤。

见示范

table_name数据

(1, 'John', 'Doe'),
(2, 'Bugs', 'Bunny'),
(3, 'John', 'Johnson'),
(4, 'John', 'Doe'),
(5, 'John', 'Johnson')

询问

SELECT t1.*
FROM table_name AS t1
LEFT JOIN table_name AS t2
ON t1.firstname = t2.firstname
AND (t1.lastname > t2.lastname
OR (t1.firstname = t1.firstname AND t1.lastname = t2.lastname AND t1.id > t2.id))
WHERE t2.id IS NULL;

结果

| id | firstname | lastname |
|----|-----------|----------|
|  1 |      John |      Doe |
|  2 |      Bugs |    Bunny |

有序子查询

编辑

我最初使用有序子查询的答案是在MySQL 5.7.5之前编写的,由于的更改,该版本不再适用ONLY_FULL_GROUP_BY。请改用上面的排除联接示例。

注意也很重要;当ONLY_FULL_GROUP_BY处于关闭状态(现有到MySQL 5.7.5原始行为),使用的GROUP BY而无需聚合函数可以产生意外的结果,因为MySQL是自由选择任何数据集内的值被分组[原文如此]

意味着可以检索与检索到的行不相关IDor或lastnamevalue 。firstname


警告

与MySQL搭配使用时,GROUP BY可能无法产生预期的结果ORDER BY

请参阅测试用例示例

为了确保获得预期结果,最好的实现方法是使用有序子查询来过滤结果集范围。

table_name数据

(1, 'John', 'Doe'),
(2, 'Bugs', 'Bunny'),
(3, 'John', 'Johnson')

询问

SELECT * FROM (
    SELECT * FROM table_name ORDER BY ID DESC
) AS t1
GROUP BY FirstName

结果

| ID | first |    last |
|----|-------|---------|
|  2 |  Bugs |   Bunny |
|  3 |  John | Johnson |

比较方式

GROUP BY与结合使用时展示出意想不到的结果ORDER BY

询问

SELECT * FROM table_name GROUP BY FirstName ORDER BY ID DESC

结果

| ID | first |  last |
|----|-------|-------|
|  2 |  Bugs | Bunny |
|  1 |  John |   Doe |

3
迄今为止最完整的答案。在第一个查询中将“ ID desc”更改为“ ID asc”,使我们可以检索“ John Doe”或“ John Johnson”。在第二个查询中更改“ ID desc”不会产生此效果。
卡拉

在postgres上,您不确定MySQL是否需要组中的ID。
Sachin Prasad 2015年

一个SELECT语句中的GROUP BY列A ORDER BY列B是否始终可以与最新版本的MyriaDB一起正常使用?
尼尔·戴维斯

@NealDavis按照MariaDB手册Ordering is done after grouping.,因此在此用例中请注意,此外,MariaDB会在子查询中忽略ORDER BY (根据SQL标准)而不使用LIMIT。你会想使用Window Function更多的澄清,你应该问你的问题在DBA stackexchange,因为这是与MySQL的一个问题
fyrye

1
@NateS否,GROUP BY可以选择分组数据集中的任何值,除非在这些列上使用了聚合函数来强制使用特定值。所以lastnameid可以来自任何有序行。默认情况下,原始的子查询示例在默认情况下是可以接受的,MySQL <= 5.7.4但从技术上讲仍然会遇到问题。尽管ORDER BY确实有助于防止随机选择,但从理论上讲还是可行的,但是比不使用ORDER BY子查询的可能性要小得多。
fyrye



3

怎么样

`SELECT 
    my_distinct_column,
    max(col1),
    max(col2),
    max(col3)
    ...
 FROM
    my_table 
 GROUP BY 
    my_distinct_column`

2

不确定是否可以使用MySQL执行此操作,但是可以在T-SQL中使用CTE

; WITH tmpPeople AS (
 SELECT 
   DISTINCT(FirstName),
   MIN(Id)      
 FROM People
)
SELECT
 tP.Id,
 tP.FirstName,
 P.LastName
FROM tmpPeople tP
JOIN People P ON tP.Id = P.Id

否则,您可能必须使用临时表。


1

正如fyrye所指出的那样,可接受的答案与ONLY_FULL_GROUP_BY尚未引入的旧版MySQL有关。使用MySQL 8.0.17(在此示例中使用),除非禁用,否则ONLY_FULL_GROUP_BY将收到以下错误消息:

mysql> SELECT id, firstName, lastName FROM table_name GROUP BY firstName;

错误1055(42000):SELECT列表的表达式#1不在GROUP BY子句中,并且包含未聚合的列'mydatabase.table_name.id',该列在功能上不依赖于GROUP BY子句中的列;这与sql_mode = only_full_group_by不兼容

解决此问题的一种方法没有被fyrye提及,但在https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html中进行了描述,是将ANY_VALUE()函数应用于以下字段:不是在GROUP BY条款(idlastName在本例中):

mysql> SELECT ANY_VALUE(id) as id, firstName, ANY_VALUE(lastName) as lastName FROM table_name GROUP BY firstName;
+----+-----------+----------+
| id | firstName | lastName |
+----+-----------+----------+
|  1 | John      | Doe      |
|  2 | Bugs      | Bunny    |
+----+-----------+----------+
2 rows in set (0.01 sec)

如上述文档所述,

在这种情况下,MySQL将忽略每个名称组中地址值的不确定性,并接受查询。如果您根本不在乎为每个组选择未聚合列的哪个值,这可能会很有用。ANY_VALUE()不是集合函数,不同于SUM()或的函数COUNT()。它只是起到抑制不确定性测试的作用。


为了澄清起见,我特别避免建议使用,ANY_VALUE()因为我的回答和评论集中在防止模棱两可和不可预测的结果集上。如函数名所暗示的那样,它可能导致从选定行中检索任何值。我建议使用MAXMIN代替。
fyrye

0

当使用分组依据和顺序时,请记住,MySQL是唯一的数据库,允许在select语句的一部分中按分组和/或顺序使用列。

因此,例如:从表组中按列2选择列1,按列3选择顺序

在其他数据库(例如Postgres,Oracle,MSSQL等)中将无法运行。您必须在这些数据库中执行以下操作

从表组中按列2选择列1,列2,列3,列3按顺序

仅提供一些信息,以防您将当前代码迁移到另一个数据库或开始在另一个数据库中工作并尝试重用代码。


-2

您可以使用分组依据显示不同的值以及相应的字段。

select * from tabel_name group by FirstName

现在您得到如下输出:

ID    FirstName     LastName
2     Bugs          Bunny
1     John          Doe


如果你想回答像

ID    FirstName     LastName
1     John          Doe
2     Bugs          Bunny

然后使用此查询,

select * from table_name group by FirstName order by ID

2
按以下顺序分组时,这并不总是会产生预期的结果
fyrye 2014年

-3
SELECT DISTINCT(firstName), ID, LastName from tableName GROUP BY firstName

将是IMO的最佳选择


32
这是行不通的,它还会将ID和姓氏带入不同的评估中。
卢多-纪录

2
这与DISTINCT(firstName,ID,LastName)相同
Tom Taylor

-4
SELECT DISTINCT (column1), column2
FROM table1
GROUP BY column1

1
DISTINCT()不是功能。DISTINCT和GROUP BY也在做相同的事情,因此没有理由将两者都放。
Marki555

这不是一个有效的语句,您不能同时使用DISTINCT或Group By。
heshanlk
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.