2008-08-24 5 views
4

Ich habe eine Postgres-Datenbank mit einer Benutzertabelle (Benutzer-ID, Vorname, Nachname) und eine Usermetadata-Tabelle (Benutzer-ID, Code, Inhalt, erstellt Datetime). Ich speichere verschiedene Informationen über jeden Benutzer in der Benutzermetadaten-Tabelle nach Code und führe einen vollständigen Verlauf. so beispielsweise ein Benutzer (Benutzer-ID 15) hat die folgende Metadaten:Beitritt der letzten Usermetadata Tags zu Benutzerzeilen

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' 

Ich brauche eine Liste aller meiner Benutzer und den aktuellsten Wert von jeder der verschiedenen usermetadata Codes zu holen. Ich habe das programmatisch gemacht und es war natürlich sehr langsam. Das Beste, was ich in SQL herausfinden konnte, war Sub-Selects zu verbinden, die ebenfalls langsam waren und ich musste für jeden Code einen tun.

Antwort

1

Ich nehme an, Sie nicht bereit sind, Ihr Schema zu ändern, so fürchte ich meine answe keine große Hilfe sein könnte, aber hier geht ...

Eine mögliche Lösung wäre es, die Zeitfeld haben leer, bis es durch einen neueren Wert ersetzt wurde, wenn Sie stattdessen das 'Verfalldatum' eingeben. Eine andere Möglichkeit besteht darin, die Tabelle mit einer "aktiven" Spalte zu erweitern, aber das würde eine gewisse Redundanz einführen.

Die klassische Lösung wäre, sowohl die Felder 'Gültig von' als auch 'Gültig bis' zu haben, in denen die Felder 'Gültig bis' leer sind, bis ein anderer Eintrag gültig wird. Dies kann leicht durch Verwendung von Triggern oder ähnlichem gehandhabt werden. Durch die Verwendung von Einschränkungen, um sicherzustellen, dass nur ein Element jedes Typs gültig ist, wird die Datenintegrität sichergestellt.

Gemeinsam ist, dass es eine einzige Möglichkeit gibt, die Menge der aktuellen Felder zu bestimmen. Sie würden einfach alle Einträge mit dem aktiven Benutzer und einem NULL-Gültig-zu-Datum oder einem Abnutzungsdatum oder einem wahren Aktiven auswählen.

Sie könnten den Wikipedia-Eintrag unter temporal databases und den Artikel A consensus glossary of temporal database concepts interessieren.

6

Das ist eigentlich nicht so schwer in PostgreSQL zu tun, weil es die Klausel "DISTINCT ON" in seiner SELECT-Syntax hat (DISTINCT ON ist kein Standard-SQL).

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

, dass die zurückgegebenen Ergebnisse zu dem ersten Ergebnis pro eindeutigem Code begrenzen, und wenn Sie die Ergebnisse nach dem absteigenden erstellen Zeit sortieren, müssen Sie die neuesten jeder bekommen.

0

Ein Subselect ist die Standardmethode, um so etwas zu tun. Sie benötigen nur eine eindeutige Einschränkung für Benutzer-ID, Code und Datum - und dann können Sie Folgendes ausführen:

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