我有一个postgres数据库,其中包含用户表(userid,firstname,lastname)和usermetadata表(userid,代码,内容,创建日期时间)。我按代码在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'
我需要获取所有用户的列表以及各种用户元数据代码的最新值。我以编程方式做到了这一点,当然是神圣的缓慢。在SQL中我能想到的最好的方法是加入子选择,这也很慢,我必须为每个代码做一个。
答案 0 :(得分:6)
这在PostgreSQL中实际上并不难,因为它的SELECT语法中有"DISTINCT ON"子句(DISTINCT ON不是标准SQL)。
SELECT DISTINCT ON (code) code, content, createtime
FROM metatable
WHERE userid = 15
ORDER BY code, createtime DESC;
这会将返回的结果限制为每个唯一代码的第一个结果,如果按创建时间降序对结果进行排序,则会得到最新的结果。
答案 1 :(得分:1)
我想你不愿意修改你的架构,所以我担心我的回答可能没什么帮助,但是这里有......
当您插入“弃用日期”时,一种可能的解决方案是将时间字段设置为空,直到它被更新的值替换为止。另一种方法是使用“活动”列扩展表,但这会引入一些冗余。
经典的解决方案是同时包含“Valid-From”和“Valid-To”字段,其中“Valid-To”字段为空,直到其他条目变为有效。这可以通过使用触发器或类似方法轻松处理。使用约束来确保每种类型只有一个有效的项目将确保数据的完整性。
这些共同点是有一种确定当前字段集的方法。您只需选择活动用户的所有条目以及NULL“有效期”或“弃用日期”或真正的“有效”。
您可能有兴趣查看temporal databases上的维基百科条目和文章A consensus glossary of temporal database concepts。
答案 2 :(得分:0)
子选择是执行此类操作的标准方法。您只需要在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