Ich versuche, eine Abfrage zu erstellen, die den nächstgelegenen Wert aus einer Tabelle findet und deren ID in die resultierende Tabelle zurückgibt.
Unten finden Sie ein Beispiel, das die Situation besser beschreiben sollte.
Beispieldaten
Diese beiden Tabellen sind in der SQL-Datenbank vorhanden.
Haupttisch
+----+-------------+
| ID | Measurement |
+----+-------------+
| 1 | 0.24 |
| 2 | 0.5 |
| 3 | 0.14 |
| 4 | 0.68 |
+----+-------------+
Nachschlagwerk
+----+---------------+
| ID | Nominal Value |
+----+---------------+
| 1 | 0.1 |
| 2 | 0.2 |
| 3 | 0.3 |
| 4 | 0.4 |
| 5 | 0.5 |
| 6 | 0.6 |
| 7 | 0.7 |
| 8 | 0.8 |
| 9 | 0.9 |
+----+---------------+
Tor
Dies ist das Ergebnis einer Abfrage. Die Messungen sollten nicht an der Grenze erfolgen (z. B. 0,25).
+----+-------------+-----------+
| ID | Measurement | Lookup ID |
+----+-------------+-----------+
| 1 | 0.24 | 2 |
| 2 | 0.5 | 5 |
| 3 | 0.14 | 1 |
| 4 | 0.68 | 7 |
+----+-------------+-----------+
Gibt es eine Abfrage, die ein solches Ergebnis zurückgeben könnte?
Antworten:
Einige Abfragen, die für Postgres 9.3 getestet und optimiert wurden. Alle geben das gleiche zurück, alle sind im Grunde Standard-SQL, aber kein RDBMS unterstützt den Standard vollständig.
Insbesondere verwendet der erste einen
LATERAL JOIN
, der in Oracle oder MySQL fehlt. Test, der am besten funktioniert.Alle verwenden nur Index-Scans für die
lookup
Tabelle in Postgres. Muss natürlichlookup.nominal_value
indiziert werden. Ich schlage vor , es zu machen ,UNIQUE
weil es scheint , als ob die Spalt sollten eindeutig sein, und weil das schafft auch den wichtigen Index automatisch.LATERAL JOIN
Alle Klammern erforderlich für
UNION
. Verwandte Antwort:Postgres 9.2 wählt mehrere spezifische Zeilen in einer Abfrage aus
Korrelierte Unterabfragen in einer Unterabfrage
Korrelierte Unterabfragen in einem CTE
Verschachtelte korrelierte Unterabfragen
SQL Fiddle.
quelle
apply
Sie sind sich nicht sicher, welches DBMS Sie verwenden, aber heutzutage gibt es einige Funktionen des Support-Fensters:
quelle
Dies ist durchaus möglich, obwohl der einzige Weg, den ich mir vorstellen kann, um dies zu lösen, ziemlich ineffizient ist und wirklich nicht sehr gut skaliert.
Eine andere Lösung, die möglicherweise besser skaliert / leistungsfähiger ist, verwendet geordnete Fensterfunktionen (verfügbar unter SQL Server 2012 und 2014 sowie einigen anderen Datenbankplattformen, jedoch nicht unter Azure).
Wenn bei dieser Abfrage weiterhin Leistungsprobleme auftreten, erstellen Sie eine temporäre Nachschlagetabelle, füllen Sie sie mit den Zeilen aus "lkp" und verbinden Sie "t" und "lkp" wie oben beschrieben. Ich würde der temporären Tabelle wahrscheinlich einen Index wie geben
Welche Lösung für Sie am besten geeignet ist, hängt in erster Linie davon ab, wie viele Daten Sie haben. Probieren Sie die verschiedenen Lösungen aus.
quelle
Ich hoffe, ich vermisse nichts Offensichtliches, aber die Art und Weise, wie ich dies abfragen würde, um es für eine sehr große Nachschlagetabelle zu skalieren, ist Folgendes zu beachten:
Es ist möglich, ein kompetentes DBMS (ich weiß, dass PostgreSQL dies kann) dazu zu bringen, einen Index zu verwenden
Sobald wir diese beiden Werte haben, können wir bestimmen, welcher der beiden näher ist.
Also so etwas wie ungetestet:
sollte blitzschnell sein - es sind im Grunde immer zwei Index-Lookups und nichts weiter.
Nachdem Sie dies alles geschrieben haben, sollte es möglich sein, eine Fensterfunktion zu verwenden, um nur einen Index-Scan für die beiden Kandidatenwerte auf beiden Seiten des "Mess" -Werts durchzuführen. Der obige Ansatz erfordert jedoch keine Fensterfunktionen und sollte für keine funktionieren DBMS, das einen Index "durchlaufen" kann, anstatt einen auszuführen
order by
.quelle
Ich habe Lennarts Antwort verwendet und musste nur in der Reihenfolge von absteigend auf aufsteigend ändern. Es hat wunderbar funktioniert und war nicht allzu kompliziert.
quelle