从每个组中获取最新记录

Posted

技术标签:

【中文标题】从每个组中获取最新记录【英文标题】:Get the newest record from each group 【发布时间】:2017-02-05 02:41:24 【问题描述】:

我想对特定用户从 ejabberd 存档表中聊天的每个用户的最后消息进行排序。

我使用的字段是这些

id(消息 ID) username(用户名复制) bare_peer(正在聊天的用户) txt(文字聊天) created_at(创建时间)

我想要实现的是类似的,但我需要通过bare_peer 将用户名为1_usernode 的消息分组,但只有最后的消息。

我已经测试了很多查询,但没有一个有效。 这是我尝试的第一个查询。

SELECT id, username, bare_peer, txt FROM archive where
username = '1_usernode' GROUP BY bare_peer ORDER BY created_at DESC;

这是输出。

+------+------------+-------------------------------------------------------+---------------------+
| id   | username   | bare_peer              | txt                          | created_at          |
+------+------------+------------------------+------------------------------+---------------------+
| 1095 | 1_usernode | 10_usernode@localhost  | Hello !!!                    | 2016-07-17 21:15:17 |
| 1034 | 1_usernode | 15_usernode@localhost  | hey sup ?                    | 2016-07-13 22:40:29 |
| 1107 | 1_usernode | 13_usernode@localhost  | oi                           | 2016-07-18 00:09:28 |
| 1078 | 1_usernode | 2_usernode@localhost   | Hello this is just a Test!!! | 2016-07-15 16:30:50 |
| 1101 | 1_usernode | 7_usernode@localhost   | hey                          | 2016-07-18 00:05:55 |
| 1084 | 1_usernode | 3_usernode@localhost   | Hey how are you?             | 2016-07-15 19:36:44 |
| 1085 | 1_usernode | 4_usernode@localhost   | Hey how are you doing ?      | 2016-07-17 19:20:00 |

【问题讨论】:

您的 created_at 列是否设置为日期时间数据类型? 由于您的示例输出中的所有bare_peer 都是唯一的,因此它似乎正确地遵循了您的查询。您的意思是按username 分组吗? 显示输入数据和预期输出会有所帮助。也许创建一个 sql fiddle 输出是正确的,但它给了我最旧的消息,我需要的是最新的。 使用GROUP BY 无法实现您的目标,因为GROUP BY 做了其他事情。它不从数据库返回行,而是使用从数据库中提取的数据生成新行。您发布的查询不是有效的 SQL。两个(或更多)具有相同 bare_peer 值的不同行位于同一组中。它们对id 有不同的值,但您想要SELECT id。什么id 【参考方案1】:

试试这个查询:-

SELECT archive.id, archive.max_id, archive.username, archive.bare_peer, archive.txt 
FROM archive join 
(SELECT MAX(id) max_id, username, bare_peer, txt 
FROM archivewhere username = '1_usernode' GROUP BY bare_peer)
tab on archive.id=tab.max_id

【讨论】:

它会返回最旧的消息,但还是谢谢! SELECT * FROM archive join (SELECT MAX(id) max_id, username, bare_peer, txt FROM archive where username = '1_usernode' GROUP BY bare_peer) tab on archive.id=tab.max_id 试试这个查询@RenatoCv SELECT *GROUP BY 在同一个查询中是无效的 SQL。 输出返回给我正确的最新消息的时间和 ID,以及旧消息的文本内容。它几乎可以工作了。 SELECT archive.id, archive.max_id, archive.username, archive.bare_peer, archive.txt FROM archive join (SELECT MAX(id) max_id, username, bare_peer, txt FROM archivewhere username = '1_usernode ' GROUP BY bare_peer) tab on archive.id=tab.max_id 试试这个查询 @RenatoCv【参考方案2】:

使用这个查询很有帮助。

SELECT MAX(id), username, bare_peer, txt FROM archive where
username = '1_usernode' ORDER BY created_at DESC

【讨论】:

由于隐式分组(使用了聚合函数但不存在 GROUP BY 子句),此查询返回单行,使 ORDER BY 子句无用(查询不返回无论如何,预期的结果)。【参考方案3】:

将 created_at 声明为日期时间

试试这个

DROP TABLE IF EXISTS `archive`;

CREATE TABLE `archive` (
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(50) DEFAULT NULL,
  `bare_peer` VARCHAR(50) DEFAULT NULL,
  `txt` TEXT,
  `created_at` DATETIME DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=INNODB  DEFAULT CHARSET=latin1;

/*表archive的数据*/

INSERT  INTO `archive`(`id`,`username`,`bare_peer`,`txt`,`created_at`) 
VALUES (1034,'1_usernode','15_usernode@localhost','hey sup ?','2016-07-13 22:40:29'),
(1078,'1_usernode','2_usernode@localhost','Hello this IS just a Test!!!','2016-07-15 16:30:50'),
(1084,'1_usernode','3_usernode@localhost','Hey how are you?','2016-07-15 19:36:44'),
(1085,'1_usernode','4_usernode@localhost','Hey how are you doing ?','2016-07-17 19:20:00'),
(1095,'1_usernode','10_usernode@localhost','Hello !!!','2016-07-17 21:15:17'),
(1101,'1_usernode','7_usernode@localhost','hey','2016-07-18 00:05:55'),
(1107,'1_usernode','13_usernode@localhost','oi','2016-07-18 00:09:28');

然后运行您的查询

SELECT id, username, bare_peer, txt FROM archive where
username = '1_usernode' GROUP BY bare_peer ORDER BY created_at DESC;

【讨论】:

如果我只是修改有问题的列,它是否仍然有效? 我用您的数据创建了第二个名为 archive2 的表,并添加了更多日期较早的数据。但它总是返回给我最旧的消息。【参考方案4】:

试试下面的代码:-

select m.*
from
messages m
inner join (
select max(id) as maxid
from messages
group By (if(username > bare_peer,  username, bare_peer)), 
(if(username > bare_peer,  bare_peer, username))
) t1 on m.id=t1.maxid ;

m 是消息表的别名

【讨论】:

【参考方案5】:

您希望每个用户名和 bare_peer 的条目都带有 max(created_at)。 在 mysql 中做到这一点的一种方法是使用“拥有”,但我不喜欢那样。 我会首先获取每个条目的 max(created_at):

select username, bare_peer, max(created_at) as m_
from archive
group by username, bare_peer;

然后在该结果上加入表格:

select b.*
from (
    select username, bare_peer, max(created_at) as m_
    from archive
    group by username, bare_peer
) a
inner join archive as b on (
    a.username = b.username
    and a.bare_peer = b.bare_peer
    and a.m_ = b.created_at
)

【讨论】:

【参考方案6】:

我想知道为什么不选择 created_at 时会显示 created_at 列?而且我不知道你为什么使用group by?没有什么需要分组。

我的陈述是这样的。select id, username, bare_peer, txt, created_at from archive where username = '1_usercode' order by created_at desc

【讨论】:

我错误地从原始查询中删除了 created_at。【参考方案7】:

我用 Rahauto 的回答创建了一个临时解决方案。 我把他的查询从最新消息中返回给我正确的ID 子查询,以便我可以从它的 id 中提取消息内容。

SELECT username, bare_peer, txt, created_at FROM archive WHERE id IN (
  SELECT tab.max_id  FROM
    archive JOIN (SELECT MAX(id) max_id, username, bare_peer, txt FROM
    archive WHERE username = '1_usernode' GROUP BY bare_peer)
  tab ON archive.id=tab.max_id
);

【讨论】:

以上是关于从每个组中获取最新记录的主要内容,如果未能解决你的问题,请参考以下文章

分组并获取组中的最新记录[重复]

如何在 Spring JpaRepository 中使用 JPQL 选择组中的最新记录?

MySQL查询从具有1000万行的表中获取每个条目的最新记录

sql查询获取每个id的最新记录

SQL Server 仅更新组中的最新记录

根据最大日期获取每组的最新行