Поиск диапазона в стиле VLOOKUP в T-SQL - PullRequest
4 голосов
/ 09 июня 2011

Вот каверзная проблема, я не совсем смог разобраться. Я использую SQL Server 2008, и у меня есть таблица разреженного диапазона, которая выглядит следующим образом:

Range     Profession
-----     ----------
0         Office Worker
23        Construction
54        Medical

Тогда у меня есть другая таблица со значениями, которые находятся в этих диапазонах. Я хотел бы построить запрос, который объединяет эти две таблицы и дает мне значение Profession, которое меньше или равно заданному значению. Допустим, моя другая таблица выглядит так:

Value
29
1
60

Тогда я бы хотел, чтобы мое объединение вернулось:

Value     Profession
-----     ----------
29        Construction
1         Office Worker
60        Medical

(потому что 29> 23 для строительства, но <= 54 для медицины) </p>

Можно ли каким-то образом заставить SQL согнуть мою волю таким образом, за исключением фактического выброса таблицы диапазонов для включения всех возможных значений?

Спасибо.

Ответы [ 3 ]

4 голосов
/ 09 июня 2011

Упрощенный способ сделать это - добавить еще один столбец в таблицу разреженного диапазона.

LowRange       HighRange      Profession
   0              22         Office Worker
  23              53          Construction
  54            999999         Medical

Затем используйте запрос, подобный следующему, чтобы получить диапазон (таблица 2 соответствует 29,1,60 значениям):

SELECT Table_2.JoinKey as Value, Table_1.Description as Profession 
  FROM Table_1 INNER JOIN Table_2 
          ON Table_2.JoinKey => Table_1.LowRangeKey 
             AND Table_2.JoinKey <= Table_1.HighRangeKey;
3 голосов
/ 09 июня 2011

Вы можете использовать CROSS APPLY:

select v.Value, p.Profession
from tblValues v
cross apply
   (select top(1) pr.Profession
    from tblProfessionRanges pr
    where pr.Range <= v.Value ORDER BY pr.[Range] DESC) p

Это должно быть быстрее, чем при использовании max, и не требует сохранения максимального диапазона.

2 голосов
/ 09 июня 2011

Мне кажется, я понимаю вашу проблему.Я создал таблицу с именем professions с вашими значениями и таблицу map_vals с поисковыми значениями.Затем я придумал это:

select p.range as `range1`, p.profession, v.value from professions p 
inner join map_vals v ON v.value >= p.range
where p.range = 
      (select max(p3.range) from professions p3 where p3.range <= v.value) 
order by v.value

, которое при задании этих значений ...

value   
29
0
60
1
23
54

возвращает

range1  profession  value   
0           Office Worker   0
0           Office Worker   1
23          Construction    23
23          Construction    29
54          Medical         54
54          Medical         60

РЕДАКТИРОВАТЬ:

Вы также можете использовать CROSS APPLY, как показано manfred-sorg , но для этого требуется ORDER BY DESC, или вы получите следующее:

select v.Value, p.Profession
from tblValues v
cross apply
   (select top(1) pr.Profession
    from tblProfessionRanges pr
    where pr.Range <= v.Value) p

производит

Value       Profession
----------- --------------------------------------------------
29          Office Worker
1           Office Worker
60          Office Worker

, чтобы получить желаемый результат, вам нужно изменить его на:

select v.Value, p.Profession
from tblValues v
cross apply
   (select top(1) pr.Profession
    from tblProfessionRanges pr
    where pr.Range <= v.Value ORDER BY pr.[Range] DESC) p

Value       Profession
----------- --------------------------------------------------
29          Construction
1           Office Worker
60          Medical

Однако требуемая сортировка делает его менее эффективным, чем использование MAX.

...