从每个组中获取最新记录
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 试试这个查询@RenatoCvSELECT *
和 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 选择组中的最新记录?