2015-02-26 2 views
0

Следующий код возвращает более одного матча:вернуть первый матч заданного порогового значения

IF OBJECT_ID('tempdb..#Thresholds') IS NOT NULL DROP TABLE #Thresholds 

    CREATE TABLE #Thresholds(
     [Id] [INT] IDENTITY(1,1) NOT NULL, 
     [Threshold] [FLOAT] NOT NULL 
    ) 
    INSERT INTO #Thresholds ([Threshold]) 
    SELECT 0.076923 UNION 
    SELECT 0.153846 UNION 
    SELECT 0.230769 UNION 
    SELECT 0.307692 UNION 
    SELECT 0.384615 UNION 
    SELECT 0.461538 UNION 
    SELECT 0.538461 UNION 
    SELECT 0.615384 UNION 
    SELECT 0.692307 UNION 
    SELECT 0.76923 UNION 
    SELECT 0.846153 UNION 
    SELECT 0.923076 UNION 
    SELECT 1 

    IF OBJECT_ID('tempdb..#DataToBeJoined') IS NOT NULL DROP TABLE #DataToBeJoined 

    CREATE TABLE #DataToBeJoined(
     [Value] [FLOAT] NOT NULL 
    ) 
    INSERT INTO #DataToBeJoined ([Value]) 
    SELECT 0.25 UNION ALL 
    SELECT 0.5 UNION ALL 
SELECT 0.5 UNION ALL 
    SELECT 0.1 

SELECT 
    * 
FROM #DataToBeJoined AS a 
INNER JOIN #Thresholds AS b ON a.Value >= b.Threshold 

Как следует:

Value Id Threshold 
0.1  1 0.076923 
0.25 1 0.076923 
0.25 2 0.153846 
0.25 3 0.230769 
0.5  1 0.076923 
0.5  2 0.153846 
0.5  3 0.230769 
0.5  4 0.307692 
0.5  5 0.384615 
0.5  6 0.461538 

То, что я заинтересован в возвращает только ближайший матч следующим образом:

Value Id Threshold 
    0.1  1 0.076923 
    0.25 3 0.230769 
    0.5  6 0.461538 
0.5  6 0.461538 

Любые идеи?

PS:

Найдено это предварительное решение:

select *, 
    (select top 1 Threshold 
    from #Thresholds 
    where #Thresholds.Threshold >= t.Value 
    order by ABS(t.Value - #Thresholds.Threshold) desc) as Threshold 
from #DataToBeJoined t 
+0

Это очень просто, row_number() над (раздел по приказу значения по порог desc) как rn ,,,,,, где rn = 1 –

+0

Спасибо, ответьте на сообщение pls. Я думаю, что я нашел решение ... – cs0815

+0

Вы хотите, чтобы ближайший матч был выше или ниже? – Jonny

ответ

2

Я думаю, что это получает то, что вы хотите (по крайней мере, ответы на мой запрос соответствует ожидаемому).

SELECT Value, Id, Threshold FROM (
    SELECT *, ROW_NUMBER() 
    OVER (PARTITION BY Value ORDER BY ABS(Value - Threshold)) as rn 
    FROM #DataToBeJoined AS a 
    CROSS JOIN #Thresholds AS b 
) as subselect 
WHERE rn = 1 
+0

, но вопрос <= not abs по-прежнему +1 – Paparazzi

+0

Это выглядит многообещающим, но не работает, если я добавляю еще одну строку: SELECT 0.5 UNION, поэтому, даже если я введу 4 строки, он возвращает 3 строки в результате ... – cs0815

+0

@csetzkorn Ответ так же хорош, как вопрос. – Paparazzi

1
;WITH CTE AS (
SELECT * 
    ,ROW_NUMBER() OVER (PARTITION BY Value ORDER BY Threshold DESC) rn 
FROM #Thresholds) 
SELECT * 
FROM CTE 
WHERE rn = 1 
-1

если вставить порог в порядке возрастания, то можете сократить чуток

select #DataToBeJoined.value, max(#Thresholds.ID), max(#Thresholds.Threshold) 
    from #DataToBeJoined 
    join #Thresholds 
    on #Thresholds.value <= #DataToBeJoined.Value 
group by #DataToBeJoined.value 

, если не в порядке

select * 
from 
(
select #DataToBeJoined.value, #Thresholds.ID, #Thresholds.Threshold 
    , row_number() over (partition by #DataToBeJoined.value order by #Thresholds.Threshold desc) as rn 
    from #DataToBeJoined 
    join #Thresholds 
    on #Thresholds.value <= #DataToBeJoined.Value 
) st 
where st.rn = 1 
+0

извините, что вы подразумеваете под «если вы вводите порог в порядке возрастания» - я всегда думал, что набор основанного подхода не знает порядка, пока вы не будете использовать ORDER BY – cs0815

+0

. Какая часть «Если вы вводите ввод в порядке возрастания» не ясна? Значение Insert не является основанной на наборе. Ваши вставки в порядке возрастания. Вы протестировали решение? – Paparazzi

+0

Да и не работает - извините. Даже если вы вставляете что-то в порядке на SQL-сервере, это означает что-то IMHO, поэтому я смущен вашим запросом. – cs0815