Ich habe ungefähr eine Milliarde Datenzeilen in einer Tabelle mit einem Namen und einer Ganzzahl im Bereich von 1-288. Für einen bestimmten Namen ist jedes int eindeutig, und nicht jede mögliche Ganzzahl im Bereich ist vorhanden - daher gibt es Lücken.
Diese Abfrage generiert einen Beispielfall:
--what I have:
SELECT *
FROM ( VALUES ('foo', 2),
('foo', 3),
('foo', 4),
('foo', 10),
('foo', 11),
('foo', 13),
('bar', 1),
('bar', 2),
('bar', 3)
) AS baz ("name", "int")
Ich möchte eine Nachschlagetabelle mit einer Zeile für jeden Namen und jede Folge zusammenhängender Ganzzahlen generieren. Jede solche Zeile würde enthalten:
Name - der Wert des Namens
Spaltenstart - die erste Ganzzahl in der zusammenhängenden Sequenz
Ende - der letzte Wert in der zusammenhängenden Sequenz
Spanne - Ende - Anfang + 1
Diese Abfrage generiert eine Beispielausgabe für das obige Beispiel:
--what I need:
SELECT *
FROM ( VALUES ('foo', 2, 4, 3),
('foo', 10, 11, 2),
('foo', 13, 13, 1),
('bar', 1, 3, 3)
) AS contiguous_ranges ("name", "start", "end", span)
Weil ich so viele Zeilen habe, ist effizienter besser. Das heißt, ich muss diese Abfrage nur einmal ausführen, es ist also nicht unbedingt erforderlich.
Danke im Voraus!
Bearbeiten:
Ich sollte hinzufügen, dass PL / pgSQL-Lösungen willkommen sind (bitte erläutern Sie alle Fancy Tricks - ich bin noch neu in PL / pgSQL).
quelle
Antworten:
Wie wäre es mit
with recursive
Testansicht:
Abfrage:
Ergebnis:
Es würde mich interessieren, wie sich das auf Ihre Milliardenzeilentabelle auswirkt.
quelle
Sie können dies mit Fensterfunktionen tun. Die Grundidee ist , zu verwenden
lead
undlag
Funktionen Windowing Reihen vor zu ziehen und hinter der aktuellen Zeile. Dann können wir berechnen, ob wir den Anfang oder das Ende der Sequenz haben:(Ich habe eine Ansicht verwendet, damit die Logik unten leichter zu befolgen ist.) Jetzt wissen wir also, ob die Zeile ein Anfang oder ein Ende ist. Wir müssen das in einer Reihe zusammenfassen:
Sieht für mich richtig aus :)
quelle
Eine weitere Lösung für Fensterfunktionen. Keine Ahnung von Effizienz, ich habe den Ausführungsplan am Ende hinzugefügt (obwohl es bei so wenigen Zeilen wahrscheinlich keinen großen Wert hat). Wenn Sie herumspielen wollen: SQL-Fiddle-Test
Tabelle und Daten:
Abfrage:
Abfrageplan
quelle
Unter SQL Server würde ich eine weitere Spalte mit dem Namen previousInt hinzufügen:
Ich würde eine CHECK-Einschränkung verwenden, um sicherzustellen, dass previousInt <int und eine FK-Einschränkung (name, previousInt) auf (name, int) verweisen, und ein paar weitere Einschränkungen, um die wasserdichte Datenintegrität sicherzustellen. Die Auswahl von Lücken ist dabei trivial:
Um dies zu beschleunigen, könnte ich einen gefilterten Index erstellen, der nur Lücken enthält. Dies bedeutet, dass alle Ihre Lücken vorberechnet werden, sodass die Auswahl sehr schnell erfolgt und Einschränkungen die Integrität Ihrer vorberechneten Daten sicherstellen. Ich benutze solche Lösungen oft, sie sind überall auf meinem System.
quelle
Sie können nach der Tabibitosan-Methode suchen:
Grundsätzlich gilt:
Ich finde diese Leistung besser:
quelle
ein grober Plan:
Wiederholen Sie den Vorgang ab 2., bis keine Aktualisierung mehr erfolgt. Von da an wird es kompliziert, Gordian, mit einer Gruppierung über max. Ich würde wohl eine Programmiersprache wählen.
PS: Eine schöne Beispieltabelle mit ein paar Beispielwerten wäre in Ordnung, die von jedem verwendet werden könnte, so dass nicht jeder seine Testdaten von Grund auf neu erstellt.
quelle
Diese Lösung ist inspiriert von Antwort nate c unter Verwendung von Fensterfunktionen und der OVER-Klausel. Interessanterweise kehrt diese Antwort zu Unterabfragen mit externen Referenzen zurück. Es ist möglich, die Zeilenkonsolidierung mit einer anderen Ebene von Fensterfunktionen abzuschließen. Es mag nicht besonders hübsch aussehen, aber ich gehe davon aus, dass es effizienter ist, da es die integrierte Logik der leistungsstarken Fensterfunktionen nutzt.
Ich erkannte aus Nates Lösung, dass der Anfangssatz von Zeilen bereits die erforderlichen Flags erzeugt hatte, um 1) die Werte für den Start- und Endbereich auszuwählen UND 2) die zusätzlichen Zeilen dazwischen zu eliminieren. In der Abfrage sind Unterabfragen nur aufgrund von Einschränkungen der Fensterfunktionen, die die Verwendung von Spaltenaliasnamen einschränken, zwei Mal tief verschachtelt. Logischerweise hätte ich die Ergebnisse mit nur einer verschachtelten Unterabfrage erzeugen können.
Ein paar andere Hinweise : Das Folgende ist Code für SQLite3. Der SQLite-Dialekt ist von postgresql abgeleitet, ist also sehr ähnlich und funktioniert möglicherweise sogar unverändert. Ich habe die OVER-Klauseln um Rahmeneinschränkungen erweitert, da die
lag()
undlead()
-Funktionen vor bzw. nach jeweils nur ein einziges Zeilenfenster benötigen (es war also nicht erforderlich, den Standardsatz aller vorhergehenden Zeilen beizubehalten). Ich habe mich auch für die Namen entschiedenfirst
undlast
da ist das Wortend
reserviert.Die Ergebnisse sind genau wie die anderen Antworten, wie man erwartet:
quelle