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ürlich lookup.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
SELECT m.id, m.measurement, l.nominal_value
FROM measurement m
JOIN LATERAL (
(
SELECT nominal_value - m.measurement AS diff, nominal_value
FROM lookup
WHERE nominal_value >= m.measurement
ORDER BY nominal_value
LIMIT 1
)
UNION ALL
(
SELECT m.measurement - nominal_value, nominal_value
FROM lookup
WHERE nominal_value <= m.measurement
ORDER by nominal_value DESC
LIMIT 1
)
ORDER BY 1 -- NULLS LAST is default
LIMIT 1
) l ON TRUE;
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
SELECT id, measurement
,CASE WHEN hi - measurement > measurement - lo
THEN lo
ELSE COALESCE(hi, lo) -- cover all possible NULL values
END AS nominal_value
FROM (
SELECT id, measurement
,(SELECT nominal_value
FROM lookup
WHERE nominal_value >= m.measurement
ORDER BY nominal_value
LIMIT 1) AS hi
,(SELECT nominal_value
FROM lookup
WHERE nominal_value <= m.measurement
ORDER by nominal_value DESC
LIMIT 1) AS lo -- cover possible NULL values
FROM measurement m
) sub;
Korrelierte Unterabfragen in einem CTE
WITH cte AS (
SELECT id, measurement
,(SELECT nominal_value
FROM lookup
WHERE nominal_value >= m.measurement
ORDER BY nominal_value
LIMIT 1) AS hi
,(SELECT nominal_value
FROM lookup
WHERE nominal_value <= m.measurement
ORDER by nominal_value DESC
LIMIT 1) AS lo
FROM measurement m
)
SELECT id, measurement
,CASE WHEN hi - measurement > measurement - lo
THEN lo
ELSE COALESCE(hi, lo) -- cover all possible NULL values
END AS nominal_value
FROM cte;
Verschachtelte korrelierte Unterabfragen
SELECT id, measurement
,(SELECT nominal_value FROM (
(
SELECT nominal_value - m.measurement, nominal_value
FROM lookup
WHERE nominal_value >= m.measurement
ORDER BY nominal_value
LIMIT 1
)
UNION ALL
(
SELECT m.measurement - nominal_value, nominal_value
FROM lookup
WHERE nominal_value <= m.measurement
ORDER by nominal_value DESC
LIMIT 1
)
ORDER BY 1
LIMIT 1
) sub
) AS nominal_value
FROM measurement m;
SQL Fiddle.