SQL查询以获取最新用户更新记录

时间:2018-07-31 22:12:17

标签: sql group-by

我有一个postgres数据库,其中包含一个审核日志表,其中包含文档更新的历史日志。它包含更新了哪个文档,更新了哪个字段,哪个用户进行了更改以及何时进行了更改。一些样本数据如下所示:

doc_id  | user_id |      created_date      |    field    |  old_value    |  new_value   
--------+---------+------------------------+-------------+---------------+------------
 A      | 1       | 2018-07-30 15:43:44-05 | Title       |               | War and Piece
 A      | 2       | 2018-07-30 15:45:13-05 | Title       | War and Piece | War and Peas
 A      | 1       | 2018-07-30 16:05:59-05 | Title       | War and Peas  | War and Peace
 B      | 1       | 2018-07-30 15:43:44-05 | Description | test 1        | test 2
 B      | 2       | 2018-07-30 17:45:44-05 | Description | test 2        | test 3

您可以看到文档Title的{​​{1}}被更改了三次,首先是用户A,然后是用户1,然后是用户{{1} }。

基本上,我需要知道哪个用户是最后一个更新特定文档上的字段的用户。因此,例如,我需要知道用户2是最后一个更新文档1上的1字段的用户。我不太在乎它发生的时间,只在乎文档,字段和用户。

因此示例输出将如下所示:

Title

看起来它应该是写起来相当简单的查询,但是我遇到了一些麻烦。我认为A会很好,但是问题是,如果我按doc_id | field | user_id --------+-------------+--------- A | Title | 1 B | Description | 2 分组,则会丢失用户数据:

group by

我可以将这些结果表重新加入到doc_id表中,但是我需要基于select doc_id, max(created_date) from document_history group by doc_id; doc_id | max --------+------------------------ B | 2018-07-30 15:00:00-05 A | 2018-07-30 16:00:00-05 和时间戳,这似乎不太正确。如果两个人在同一时间编辑文档,我将获得该文档和字段的多行。也许那是不太可能的,我不应该为此担心,但仍然...

有什么想法可以在单个查询中做到这一点?

2 个答案:

答案 0 :(得分:2)

您要过滤记录,因此请考虑where,而不是group by

select dh.*
from document_history
where dh.created_date = (select max(dh2.created_date) from document_history dh2 where dh2.doc_id = dh.doc_id);

在大多数数据库中,如果您在group by上有索引,它的性能将比document_history(doc_id, created_date)好。

答案 1 :(得分:0)

如果您的DBMS支持窗口函数(例如PostgreSQL,SQL Server;也称为Oracle中的分析函数),则可以执行以下操作(SQLFiddle与Postgres,其他系统的语法可能略有不同):

http://sqlfiddle.com/#!17/981af/4

SELECT DISTINCT
    doc_id, field, 
    first_value(user_id) OVER (PARTITION BY doc_id, field ORDER BY created_date DESC) as last_user
FROM get_last_updated

first_value() OVER (... ORDER BY x DESC)对窗口框架/分区进行降序排列,然后采用第一个值,即您的最新时间戳。

我添加了DISTINCT以得到您期望的结果。 window函数只是向您的SELECT结果中添加了一个新列,但在同一分区中具有相同的值。如果不需要它,请将其删除,然后便可以使用原始数据以及新的韩元信息。