2008-08-24 31 views
4

我有一個用戶表(userid,firstname,lastname)和一個usermetadata表(用戶標識,代碼,內容,創建日期時間)的postgres數據庫。我通過代碼將關於每個用戶的各種信息存儲在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' 

我要去找我的所有用戶的列表和最近各個不同usermetadata碼的值。我以編程的方式完成了這個任務,當然這很慢。我能想出的最好的辦法是在SQL中加入子選擇,這些選擇也很慢,我必須爲每個代碼執行一次。

回答

1

我想你是不是願意修改您的架構,所以我怕我answe可能不會有很大幫助,但在這裏不用...

一個可能的解決辦法是有時間字段直到它被更新的值替換爲空時,而是插入「棄用日期」。另一種方法是用「活動」列來擴展表格,但這會引入一些冗餘。

經典的解決方案是將「有效來源」字段和「有效來源」字段的「有效到」字段爲空,直到某些其他條目生效爲止。這可以通過使用觸發器或類似的方法輕鬆處理。使用約束來確保每種類型中只有一個有效的項目可以確保數據的完整性。

這些共同之處在於確定當前字段集合的方法是單一的。您只需選擇具有活動用戶的所有條目,並選擇「有效期」或「棄用日期」或真實的「有效」。

您可能會感興趣的考慮看看上temporal databases維基百科條目和文章​​A consensus glossary of temporal database concepts

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; 

這將限制返回的結果爲每唯一代碼的第一個結果,如果按創建時間降序對結果進行排序,你會得到最新的每個。

0

子選擇是做這種事情的標準方式。您只需在用戶標識,代碼和日期上使用唯一約束 - 然後您可以運行以下操作:

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