выбрать пропущенную строку из таблицы - PullRequest
2 голосов
/ 31 марта 2011
temperature  decrease_capacity
----------    ----------------
125           5
150           10
175           15

... и т.д. если я хочу выбрать уменьшение_производительности для температуры = 166, как я получу.

Ответы [ 3 ]

0 голосов
/ 31 марта 2011

Если линейная интерполяция является желаемым результатом, то следующий чрезвычайно уродливый, глупый и, вероятно, медленный запрос может привести к такому результату.Я сократил имена полей до t и dc.Я говорю «может», потому что с этим запросом огромное предостережение . Как написано, предполагается, что значение lower_capacity всегда увеличивается при повышении температуры (я понятия не имею, правда это или нет).select max(dc) from test where t <= 166 является одной частью, которая основана на этом предположении.Это также предполагает, что поля являются значениями с плавающей запятой (в противном случае будет выполняться целочисленная математика, как написано).

Ох ... и предостережение # 3.Это также может привести к сбою, если указанная температура будет меньше или больше, чем все значения температуры в таблице.

select (select max(dc) from test where t <= 166) + 
       (166 - (select max(t) from test where t <= 166)) * 
       ((select min(dc) from test where t >= 166) - 
        (select max(dc) from test where t <= 166)) / 
       ((select min(t) from test where t >= 166) - 
        (select max(t) from test where t <= 166))

Возможно, было бы более целесообразно реализовать это как хранимую процедуру и просто выполнить отдельный SELECT.заявления и вычислить результат линейной интерполяции из этого.Было бы намного легче читать и почти наверняка более эффективно.

0 голосов
/ 31 марта 2011

Вы не указали RDBMS. При этом используются специфичные для SQL Server TOP (могут быть заменены на row_number или limit в зависимости от разновидности) и специфическая переменная SQL Server для удобства тестирования.

Я решил вернуть NULL, если 2 точки данных были недоступны.

DECLARE @SearchTemp FLOAT = 166;

WITH T(temperature, decrease_capacity) AS
(
SELECT 125.0,5.0 UNION ALL
SELECT 150.0,10 UNION ALL
SELECT 175.0,15 
), T2 AS
(
SELECT TOP 1 'L' as bound, temperature, decrease_capacity
FROM T 
WHERE temperature <= @SearchTemp
ORDER BY temperature DESC
UNION ALL
SELECT TOP 1 'U' as bound,  temperature, decrease_capacity
FROM T 
WHERE temperature >= @SearchTemp
ORDER BY temperature 
)
SELECT CASE
         WHEN COUNT(*) = 2 THEN CASE
                                  WHEN COUNT(DISTINCT temperature) = 1 THEN MAX(decrease_capacity)
                                  ELSE ((@SearchTemp-MAX(CASE WHEN bound = 'L' THEN temperature END) )/(MAX(CASE WHEN bound = 'U' THEN temperature END) -MAX(CASE WHEN bound = 'L' THEN temperature END) )) * (MAX(CASE WHEN bound = 'U' THEN decrease_capacity END)-MAX(CASE WHEN bound = 'L' THEN decrease_capacity END)) + MAX(CASE WHEN bound = 'L' THEN decrease_capacity END)
                                END
       END
FROM   T2  
0 голосов
/ 31 марта 2011

Математика для линейной интерполяции будет:

c1 + (t - t1) / (t2 - t1) * (c2 - c1)

t  = input tempurate
t1 = nearest lower temperature
t2 = nearest upper temperature
c1 = capacity belonging to t1
c2 = capacity belonging to t2

Вот несколько SQL, чтобы сделать эту математику:

declare @YourTable table (temperature int, decrease_capacity int)
insert @YourTable values (125, 5), (150, 10), (175, 15)

declare @temp int
set @temp = 166

select  case 
        when below.temperature is null then above.decrease_capacity
        when above.temperature is null then below.decrease_capacity
        else below.decrease_capacity + 1.0 *
             (@temp - below.temperature) / 
             (above.temperature - below.temperature) *
             (above.decrease_capacity - below.decrease_capacity)
        end
from    (
        select  min(temperature) as mintemp
        from    @YourTable 
        where   temperature >= @temp
        ) abovetemp
left join
        @YourTable above
on      above.temperature = abovetemp.mintemp
cross join
        (
        select  max(temperature) as maxtemp
        from    @YourTable 
        where   temperature < @temp
        ) belowtemp
left join
        @YourTable below
on      below.temperature = belowtemp.maxtemp

Пример по одатам.

...