我有一个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
和时间戳,这似乎不太正确。如果两个人在同一时间编辑文档,我将获得该文档和字段的多行。也许那是不太可能的,我不应该为此担心,但仍然...
有什么想法可以在单个查询中做到这一点?
答案 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
结果中添加了一个新列,但在同一分区中具有相同的值。如果不需要它,请将其删除,然后便可以使用原始数据以及新的韩元信息。