在字符串列上使用 GROUP BY 时未获得分组结果

Posted

技术标签:

【中文标题】在字符串列上使用 GROUP BY 时未获得分组结果【英文标题】:Not getting grouped results when using GROUP BY on a string column 【发布时间】:2019-07-27 09:49:53 【问题描述】:

我有一个收件箱表,我想在其中返回按电话号码分组的消息(例如按发件人分组的 GMail 组)。并且 sms_content 应该是 id 的最后一条消息。但是当我使用 GROUP BY 关键字时,它不会返回分组结果。

这是我的“收件箱”表。有 2 条来自号码“+123456789”的消息应该被分组。

+----+--------------+------------------------------+
| id | phone_number |         sms_content          |
+----+--------------+------------------------------+
|  1 | +123456789   | Hello, my name is            |
|  2 | +987654321   | What's up, long time no see! |
|  3 | +123456789   | John, I want to meet you!    |
+----+--------------+------------------------------+

我的第一个查询失败并显示此错误消息

select * from inbox group by phone_number

错误:查询错误:错误:列“inbox.id”必须出现在 GROUP BY 子句或在聚合函数中使用

我尝试的第二个查询没有返回按电话号码分组的结果

select *
from inbox
group by phone_number, id, sms_content
order by id desc

结果(未分组):

+----+--------------+------------------------------+
| id | phone_number |         sms_content          |
+----+--------------+------------------------------+
|  3 | +123456789   | John, I want to meet you!    |
|  2 | +987654321   | What's up, long time no see! |
|  1 | +123456789   | Hello, my name is            |
+----+--------------+------------------------------+

我希望看到的结果是这样的。电话号码字段应分组,sms_content 应显示该电话号码的最新 sms_content。

+--------------+------------------------------+
| phone_number |         sms_content          |
+--------------+------------------------------+
| +123456789   | John, I want to meet you!    |
| +987654321   | What's up, long time no see! |
+--------------+------------------------------+

【问题讨论】:

【参考方案1】:

对于这种情况,PostgreSQL 有一个有用的标准扩展:

SELECT DISTINCT ON (phone_number)
       phone_number,
       sms_content
FROM inbox
ORDER BY phone_number, id DESC

Details:

SELECT DISTINCT ON ( expression [, ...] ) 只保留给定表达式计算结果等于的每组行的第一行。

(Sample fiddle)

【讨论】:

这看起来很优雅,可惜只适用于 PostgreSQL。但就我而言,这就是我所需要的。谢谢! 你指定了PostgreSQL,当然你会得到PostgreSQL的答案。【参考方案2】:

先获取每个数字的最大id,然后加入表:

select i.phone_number, i.sms_content
from inbox i inner join (
  select phone_number, max(id) maxid
  from inbox 
  group by phone_number
) g on g.maxid = i.id and g.phone_number = i.phone_number

或不存在:

select i.phone_number, i.sms_content
from inbox i
where not exists (
  select 1 from inbox
  where phone_number = i.phone_number and id > i.id
)

【讨论】:

另外,所有答案中最快的执行时间。【参考方案3】:

试试这个:

select id,phone_number
      ,sms_content

from inbox

where id in(
            Select MAX(id) AS id
            FROM inbox
            group by phone_number
                )

【讨论】:

【参考方案4】:

你可以像这样使用row_number:

select * from (   
     select phone_number, sms_content, 
     row_number() over(partition by phone_number order by id desc) as rn
     from inbox
) t
where 
rn = 1

【讨论】:

简单地对消息进行分组似乎过于复杂。是否可以在更简单的查询中做到这一点?【参考方案5】:

选择最大(id),电话号码, 收件箱中的 sms_content 按电话号码分组

【讨论】:

错误:列“inbox.sms_content”必须出现在 GROUP BY 子句中或用于聚合函数中

以上是关于在字符串列上使用 GROUP BY 时未获得分组结果的主要内容,如果未能解决你的问题,请参考以下文章

数据库的group by有啥意义呢?

MySQL在分组(GROUP BY)结果上使用ORDER BY

Thinkphp 下 MySQL group by 接count 获得条数方法

SQL中group by问题

如何使用group by 分组查询表中所有字段信息

使用 group_by、summary 和 max() 循环 R 中的字符向量