最新のさまざまな usermetadata タグをユーザー行に結合する
-
09-06-2019 - |
質問
ユーザーテーブル(ユーザーID、名、姓)とユーザーメタデータテーブル(ユーザーID、コード、コンテンツ、作成日時)を備えた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'
すべてのユーザーのリストと、さまざまなユーザーメタデータ コードそれぞれの最新の値を取得する必要があります。私はこれをプログラムで実行しましたが、もちろん恐ろしく遅かったです。SQL でこれを行うために私が考えついた最善の方法は、サブ選択を結合することでしたが、これも時間がかかり、コードごとに 1 つずつ実行する必要がありました。
解決
あなたはあなたのスキーマを変更したくないと思うので、私のansweはあまり役に立たないかもしれないが、ここに行く...
可能な解決策の1つは、代わりに「廃止予定日」を挿入するときに、新しい値に置き換えられるまで時間フィールドを空にすることです。もう1つの方法は、「アクティブ」列を使用してテーブルを展開することですが、これにより冗長性が導入されます。
古典的な解決策は、他のエントリが有効になるまで「Valid-To」フィールドが空白である「Valid-From」フィールドと「Valid-To」フィールドの両方を使用することです。これは、トリガーなどを使用して簡単に処理できます。制約を使用して、有効な各タイプのアイテムが1つだけであることを確認すると、データの整合性が確保されます。
これらに共通するのは、現在のフィールドのセットを決定する単一の方法があることです。アクティブなユーザーとNULLの「Valid-To」、「deprecation date」、または真の「active」を持つすべてのエントリを選択するだけです。
テンポラルデータベースのWikipediaエントリをご覧になることをお勧めします。記事時間データベースの概念に関するコンセンサス用語集。
他のヒント
PostgreSQL には次の機能があるため、これを行うのは実際にはそれほど難しくありません。 「ディスティンクトオン」 SELECT 構文内の句 (DISTINCT ON は標準 SQL ではありません)。
SELECT DISTINCT ON (code) code, content, createtime
FROM metatable
WHERE userid = 15
ORDER BY code, createtime DESC;
これにより、返される結果は一意のコードごとの最初の結果に制限され、結果を作成時間の降順に並べ替えると、それぞれの最新の結果が得られます。
副選択は、この種のことを行う標準的な方法です。 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