SQLite:如何使用组合键从单个表中选择“每个用户的最新记录”?

问题描述 投票:0回答:3

我不是数据库专家,感觉我缺少一些核心 SQL 知识来解决这个问题。这是我能简单解释的情况。

背景:

我有一个 SQLite 数据库表,其中包含带时间戳的用户事件记录。记录可以通过时间戳和用户 ID 的组合来唯一标识(即,事件发生的时间以及事件与谁有关)。我理解这种情况叫做“复合主键”。该表看起来像这样(当然,删除了一堆其他列):

sqlite> select Last_Updated,User_ID from records limit 4;

Last_Updated   User_ID
-------------  --------
1434003858430  1   
1433882146115  3   
1433882837088  3   
1433964103500  2   

问题: 我如何

SELECT
获得仅包含每个用户的最新记录的结果集?

鉴于上面的示例,我想要返回的是一个如下所示的表格:

Last_Updated   User_ID
-------------  --------
1434003858430  1   
1433882837088  3   
1433964103500  2   

(请注意,结果集仅包含用户

3
的最新记录。)

实际上,此表中有大约 250 万行。

奖励:我一直在阅读有关联接、重复数据删除程序等的答案,并且我一直在谷歌上搜索教程/文章,希望能找到我所缺少的内容。我拥有广泛的编程背景,因此我可以在程序代码中对这个数据集进行重复数据删除,就像我之前做过一百次一样,但我厌倦了编写脚本来完成我认为在 SQL 中应该可以实现的操作。这就是它的用途,对吧?

那么,您认为我对 SQL 的理解从概念上讲缺少什么,为了理解为什么您为我的问题提供的解决方案实际上有效? (参考一篇真正解释实践背后理论的好文章就足够了。)我想知道为什么这个解决方案实际上有效,而不仅仅是它有效。

非常感谢您的宝贵时间!

sql sqlite greatest-n-per-group
3个回答
12
投票

你可以试试这个:

select user_id, max(last_updated) as latest
from records
group by user_id

这将为您提供每个用户的最新记录。我假设您有 user_id 和 last_updated 组合的索引。

在上面的查询中,一般来说 - 我们要求数据库对 user_id 记录进行分组。如果 user_id 1 的记录多于 1 条,则它们将全部分组在一起。从该记录集中,将选择最大的last_updated 进行输出。然后寻找下一组并在那里应用相同的操作。

如果您有复合索引,sqlite 可能只会使用该索引,因为该索引包含查询中寻址的两个字段。索引比表本身小,因此扫描或查找速度更快。


4
投票

嗯,真正的“d'oh!”时尚,问完这个问题,我就找到了答案

就我而言,答案是:

SELECT MAX(Last_Updated),User_ID FROM records GROUP BY User_ID

我认为我需要使用 JOIN 之类的东西,这让事情变得比实际需要的更加复杂。只需应用像

MAX()
这样的聚合函数即可仅选择内容与函数结果匹配的行。这意味着这个声明......

SELECT MAX(Last_Updated),User_ID FROM records

…因此将返回仅包含 1 行的结果集,即最近的事件。

但是,通过添加

GROUP BY
子句,结果集包含一行 对于每个结果“组”,即对于每个用户。我的程序员大脑不明白 GROUP BY
 是我们在 SQL 中所说的“foreach”。我想我现在明白了。

自我提醒:保持简单,愚蠢。 :)


0
投票
回复晚了,但我正在努力帮助社区。

您需要为每条记录提供唯一的 ID,然后对于每个 User_ID,您触发一个选择最新 Last_Updated 的子查询,然后使用该记录的 ID 在外部查询中选择该记录。

下面是一个例子。

SELECT * FROM records R1 WHERE ID = (SELECT ID FROM (SELECT R2.* FROM records R2 WHERE R2.User_ID = R1.User_ID ORDER BY Last_Updated DESC LIMIT 1)) GROUP BY User_ID
    
© www.soinside.com 2019 - 2024. All rights reserved.