Effiziente Zeitreihenabfrage in Postgres

8

Ich habe eine Tabelle in meiner PG db, die ungefähr so ​​aussieht:

%Vor%

Jedes referenzierte Widget hat viele dieser Elemente. Es ist immer 1 pro Tag pro Widget, aber es gibt Lücken.

Was ich erhalten möchte, ist ein Ergebnis, das alle Widgets für jedes Datum seit X enthält. Die Daten werden über generate series eingefügt:

%Vor%

Wenn es keinen Eintrag für ein Datum für eine bestimmte widget_id gibt, möchte ich das vorherige verwenden. Also sagen Sie das Widget 1337 hat keinen Eintrag am 2012-05-10, aber am 2012-05-08, dann möchte ich, dass das Resultset auch den Eintrag 2012-05-08 am 2012-05-10 anzeigt:

%Vor%

Irgendwann möchte ich dies in eine Ansicht herunterkochen, damit ich konsistente Datensätze pro Tag habe, die ich leicht abfragen kann.

Bearbeiten: Die Beispieldaten und das Ergebnisergebnis wurden klarer gemacht

    
TheDeadSerious 14.02.2013, 12:39
quelle

4 Antworten

8

SQL Fiddle

%Vor%     
Clodoaldo Neto 14.02.2013, 13:34
quelle
7

Zuerst von allen, Sie können einen viel einfacheren generate_series() -Tabellenausdruck haben. Gleichbedeutend mit Ihrem (außer absteigender Reihenfolge, das dem Rest Ihrer Frage sowieso widerspricht):

%Vor%

Der Typ date wird bei der Eingabe automatisch in timestamptz umgewandelt. Der Rückgabetyp ist timestamptz in beide Richtungen. Ich verwende unten eine Unterabfrage, sodass ich sofort auf die Ausgabe in date umstellen kann.

Weiter , max() als Fensterfunktion gibt genau das zurück, was Sie brauchen: Der höchste Wert seit frame beginnt, NULL -Werte zu ignorieren. Darauf aufbauend erhalten Sie eine radikal einfache Abfrage.

Für eine gegebene widget_id

Sehr wahrscheinlich schneller als mit CROSS JOIN oder WITH RECURSIVE :

%Vor%

- & gt; sqlfiddle

Mit dieser Abfrage können Sie beliebige Spalten von score in die endgültige SELECT -Liste setzen. Ich stelle s. * Zur Vereinfachung. Wählen Sie Ihre Spalten.

Wenn Sie Ihre Ausgabe mit dem ersten Tag beginnen möchten, der tatsächlich eine Punktzahl hat, ersetzen Sie einfach die letzte LEFT JOIN durch JOIN .

Generisches Formular für alle widget_ids

Hier verwende ich CROSS JOIN , um für jedes Widget an jedem Datum eine Zeile zu erzeugen.

%Vor%

- & gt; sqlfiddle

    
Erwin Brandstetter 14.02.2013 14:51
quelle
2

Unter Verwendung Ihrer Tabellenstruktur habe ich den folgenden rekursiven CTE erstellt, der mit Ihrem MIN (For_Date) beginnt und inkrementiert, bis er den MAX (For_Date) erreicht. Nicht sicher, ob es einen effizienteren Weg gibt, aber das scheint gut zu funktionieren:

%Vor%

Hier ist die SQL Fiddle .

Und die zurückgegebenen Ergebnisse (formatieren Sie das Datum wie Sie möchten):

%Vor%

Beachten Sie, dass davon ausgegangen wird, dass das Feld "For_Date" ein Datum ist. Wenn es eine Uhrzeit enthält, müssen Sie möglicherweise stattdessen das Intervall "1 Tag" in der obigen Abfrage verwenden.

Hoffe, das hilft.

    
sgeddes 14.02.2013 13:23
quelle
0

Die Daten:

%Vor%

Die Abfrage:

%Vor%

Das Ergebnis:

%Vor%     
wildplasser 14.02.2013 19:42
quelle

Tags und Links