将最新的各种usermetadata标签连接到用户行

时间:2020-03-05 18:42:37  来源:igfitidea点击:

我有一个Postgres数据库,其中包含一个用户表(用户ID,名,姓)和一个用户元数据表(用户ID,代码,内容,创建的日期时间)。我通过代码将有关每个用户的各种信息存储在usermetadata表中,并保留完整的历史记录。因此,例如,用户(用户ID 15)具有以下元数据:

15, 'QHS', '20', '2008-08-24 13:36:33.465567-04'  
15, 'QHE', '8', '2008-08-24 12:07:08.660519-04'  
15, 'QHS', '21', '2008-08-24 09:44:44.39354-04'  
15, 'QHE', '10', '2008-08-24 08:47:57.672058-04'

我需要获取所有用户的列表以及各种用户元数据代码中每个代码的最新值。我是通过编程方式完成的,这当然太慢了。我想出的最好的方法是加入子选择,这也很慢,我必须为每个代码做一次。

解决方案

回答

我想我们不愿意修改架构,所以恐怕我的回答可能没有多大帮助,但是这里...

一种可能的解决方案是,在我们插入"弃用日期"时,将时间字段留空,直到被新值替换为止。另一种方法是用"活动"列扩展表,但这会带来一些冗余。

经典的解决方案是同时具有"有效期自"和"有效期至"字段,其中"有效期至"字段为空白,直到某些其他条目变为有效为止。使用触发器或者类似工具可以轻松地解决此问题。使用约束来确保每种类型中只有一项有效,这将确保数据完整性。

这些的共同点是,有一种确定当前字段集的单一方法。我们只需使用活动用户和NULL'有效期'或者'弃用日期'或者真实的'活动'选择所有条目。

我们可能有兴趣查看有关时态数据库的Wikipedia条目和时态数据库概念的共识术语表。

回答

实际上,这在PostgreSQL中并不难做到,因为它的SELECT语法中包含" DISTINCT ON"子句(DISTINCT ON不是标准SQL)。

SELECT DISTINCT ON (code) code, content, createtime
FROM metatable
WHERE userid = 15
ORDER BY code, createtime DESC;

这样会将返回的结果限制为每个唯一代码的第一个结果,如果按创建时间降序对结果进行排序,则将获得每个结果的最新信息。

回答

子选择是执行此类操作的标准方法。我们只需要对UserId,代码和日期具有唯一约束,然后可以运行以下命令:

SELECT * 
FROM Table
JOIN (
   SELECT UserId, Code, MAX(Date) as LastDate
   FROM Table
   GROUP BY UserId, Code
) as Latest ON
   Table.UserId = Latest.UserId
   AND Table.Code = Latest.Code
   AND Table.Date = Latest.Date
WHERE
   UserId = @userId