Die eigentliche Abfrage ist komplizierter, aber das Problem, mit dem ich konfrontiert bin, kann folgendermaßen herausgearbeitet werden:
Eine Abfrage zum Filtern eines Rowsets monoton ansteigender Ganzzahlen, sodass - in der endgültigen Ergebnismenge row (n + 1) .value> = row (n) .value + 5 .
Für das eigentliche Problem, das ich lösen muss, liegt die Anzahl der Rowsets in den 1000ern.
Einige Beispiele zur Verdeutlichung:
- Wenn die Zeilen: 1,2,3,4,5: lauten, sollte die Abfrage Folgendes zurückgeben: 1
- Wenn die Zeilen: 1,5,7,10,11,12,13 sind, sollte die Abfrage Folgendes zurückgeben: 1,7,12
- Wenn die Zeilen: 6,8,11,16,20,23 sind, sollte die Abfrage Folgendes zurückgeben: 6,11,16,23
- Wenn die Zeilen: 6,8,12,16,20,23 sind, sollte die Abfrage Folgendes zurückgeben: 6,12,20
Ich habe es geschafft, die erforderlichen Ergebnisse mit der folgenden Abfrage zu erhalten, aber es scheint zu kompliziert. Kommentieren Sie die verschiedenen "..mit t (k) .." aus, um sie auszuprobieren.
Ich suche nach Vereinfachungen oder alternativen Ansätzen, um die gleichen Ergebnisse zu erzielen.
with recursive r(n, pri) as (
with t(k) as (values (1),(2),(3),(4),(5)) -- the data we want to filter
-- with t(k) as (values (1),(5),(7),(10),(11),(12),(13))
-- with t(k) as (values (6),(8),(11),(16),(20),(23))
-- with t(k) as (values (6),(8),(12),(16),(20),(23))
select min(k), 1::bigint from t -- bootstrap for recursive processing. 1 here represents rank().
UNION
select k, (rank() over(order by k)) rr -- rank() is required just to filter out the rows we dont want from the final result set, and no other reason
from r, t
where t.k >= r.n+5 and r.pri = 1 -- capture the rows we want, AND unfortunately a bunch of rows we dont want
)
select n from r where pri = 1;
row(n+1).value >= row(n).value + 5
und die Zeilen, die1,5,7,10,11,12,13
Sie sagen, sollte sie zurückgegeben werden,1,7,12
aber das stimmt nicht mit der Regel überein. Die Regel sollte auch besagen, dass Sie immer die erste Zeile zurückgeben. Wenn Sie also mit der ersten Zeile 1 beginnen,5 >= 1 + 5
ist dies falsch, sodass 5 ausgeschlossen ist. Dann7 >= 5 + 5
ist auch falsch, also sollte 7 gemäß der Regel ausgeschlossen werden, aber es ist enthalten. Ihre Regel lautet eher "Beginnen Sie mit der ersten Zeile und suchen Sie die nächste Zeile, die mindestens fünf mehr als der aktuelle Wert ist und wiederholen Sie sich"Antworten:
Das war schwer! Ich weiß nicht, ob dies einfacher ist , aber es verwendet zumindest keine Fensterfunktion und erzeugt keine Zeilen, die herausgefiltert werden müssen.
Testen
Diese Alternative scheint für sehr kleine Sets weniger effizient zu sein, aber mehr oder weniger linear in der Leistung, während das Original exponentiell träger zu sein scheint.
quelle
Normalerweise können Sie Fensteraggregatfunktionen verwenden, wenn Sie auf die Daten der vorherigen Zeile zugreifen müssen. Hier basiert die Berechnung der aktuellen Zeile jedoch auf dem vorherigen Ergebnis und nicht auf der Zeile. Für diese Art von Frage habe ich nie eine satzbasierte Lösung mit akzeptabler Leistung gefunden.
Es ist jedoch einfach, zeilenweise zu schreiben. Ich bevorzuge es, a
ROW_NUMBER
in einer temporären Tabelle zu materialisieren , dann ist das Finden der nächsten Zeile einfachn+1
:Dies geht ziemlich schnell, ich habe @ ZiggyCrueltyfreeZeitgeisters Geige entführt .
Tatsächlich handelt es sich um eine Cursor-Logik-Verarbeitung alten Stils, und ein Cursor ist möglicherweise schneller (Sie benötigen keine temporäre Tabelle plus
ROW_NUMBER
und Rekursion). Meine PostgreSQL-Kenntnisse sind sehr begrenzt und ich weiß nicht, was in PG-Land bevorzugt wird :)quelle