Given a table of OriginalValues, I would like to return both the first #Conversion record where ValueFrom is greater than or equal to the OriginalValue (nearest equal to or above), and the first #Conversion record where ValueFrom is less than the OriginalValue (nearest below), to the one output record for each OriginalValue. (eg. OriginalValue, ValueFromAbove, ValueToAbove, ValueFromBelow, ValueToBelow).
Despite having the below single result query, I can't quite figure out how to join the #Values and #Conversion tables together for the desired result. Does anyone have any ideas on how to solve this?
Also, please let me know if a cursor or any other method would be faster, I'm dealing with very large data sets (#Value will be much larger than #Conversion).
Example Table structures:
CREATE TABLE #Conversion (ConversionPeriodId int, ValueFrom float, ValueTo float)
INSERT INTO #Conversion
VALUES (1, 0, 0.001), (1, 1, 0.05), (1, 1.5, 0.5), (1, 2, 1),
(2,0,0),(2,1,1),(2,2,4)
CREATE TABLE #Values (PeriodId int, OriginalValue float)
insert into #Values
VALUES (1, 0.01),(1, 2), (1, 1.89625), (1, 1.3), (1, 7), (1, -1)
Example query for a single OriginalValue (returns nothing for outside of range eg. @OrigValue = 7, but would be nicer if it could return (7) 0, 0, 2, 1 )
DECLARE @OrigValue float = 1.89625
SELECT @OrigValue as OriginalValue, a.ValueFrom AS ValueFromAbove, a.ValueTo AS ValueToAbove,
b.ValueFrom AS ValueFromBelow, b.ValueTo AS ValueToBelow
FROM (SELECT TOP 1 * FROM #Conversion
WHERE ConversionPeriodId = 1
AND ValueFrom >= @OrigValue
ORDER BY ValueFrom ) a
FULL OUTER JOIN
(SELECT TOP 1 * FROM #Conversion WHERE ConversionPeriodId = 1
AND ValueFrom < (SELECT TOP 1 ValueFrom FROM #Conversion
WHERE ConversionPeriodId = 1
AND ValueFrom >= @OrigValue
ORDER BY ValueFrom )
ORDER BY ValueFrom DESC) b
ON a.ConversionPeriodId = b.ConversionPeriodId
AND a.ValueFrom = (SELECT TOP 1 x.ValueFrom FROM #Conversion x
WHERE x.ValueFrom > b.ValueFrom ORDER BY ValueFrom )
--OriginalValue ValueFromAbove ValueToAbove ValueFromBelow ValueToBelow
--1.89625 2 1 1.5 0.5
DROP TABLE #Conversion
DROP TABLE #Values
(I'm not sure the above query is the best way to go about this. Any optimisation suggestions would be appreciated!)
My goal is to get the entire result for #Values in one go.
Example desired result:
PeriodId OriginalValue ValueFromAbove ValueToAbove ValueFromBelow ValueToBelow
1 0.01 1 0.05 0 0.001
1 2 2 1 1.5 0.5
1 1.89625 2 1 1.5 0.5
1 1.3 1.5 0.5 1 0.05
1 7 0 0 0 0
1 -1 0 0.001 0 0
The result for 7 could instead be = 1, 7, 0, 0, 2, 1.
The PeriodId column would not be necessary unless in the query it is possible to provide multiple PeriodIds. eg. insert into #Values VALUES (1, 0.01),(2, 0.1) (I don't mind too much if it isn't at this point).