2008-08-24 8 views
4

ユーザテーブル(userid、firstname、lastname)とusermetadataテーブル(userid、code、content、created datetime)を持つpostgresデータベースがあります。 usermetadataテーブルには、各ユーザーに関するさまざまな情報がコードで保存され、完全な履歴が保存されます。そう例えば、ユーザ(ユーザID 15)は、次のメタデータがあります。最新の様々なusermetadataタグをユーザ行に追加する

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つずつ行う必要がありました。

答えて

1

一つの可能​​な解決策は、時間フィールドを持っているだろう...私はあなたがあなたのスキーマを変更して喜んじゃないと仮定し、私は私のansweがはるかに助けになることはないのではないかと心配だけど、ここに行きます代わりに「廃止予定日」を挿入すると、新しい値で置き換えられるまで空になります。別の方法は、テーブルを「アクティブな」列で展開することですが、それはいくつかの冗長性を導入します。

古典的な解決策は、他のエントリが有効になるまで 'Valid-To'フィールドが空白の「Valid-From」フィールドと「Valid-To」フィールドの両方を持つことです。これは、トリガーなどを使用して簡単に処理できます。制約を使用して、有効な各タイプの項目が1つだけあることを確認すると、データの整合性が確保されます。

これらに共通するのは、現在のフィールドのセットを判断する単一の方法があることです。アクティブなユーザとNULLの「Valid-To」または「deprecation date」または真の「active」を持つすべてのエントリを選択するだけです。

あなたは、temporal databasesと記事A consensus glossary of temporal database conceptsのWikipediaエントリーを見てみたいと思うかもしれません。

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

サブセレクトは、この種のことを行う標準的な方法です。 UserId、Code、およびDateに固有の制約が必要なだけです。次に、以下を実行できます。

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 
関連する問題