在SQL Server中匹配单个数字到最接近范围

时间:2013-04-08 10:03:41

标签: sql-server tsql sql-server-2012

我有一张表格,根据数字显示评分数字,如下所示:

  • 0-24 =新手
  • 25-49 =实习生
  • 50-74 =中等
  • 75-99 = Pro
  • 100 =超人

我需要取一个数值,并将其与上面最接近的等效等级相匹配。因此, 80 等同于 Pro ,因为它符合基本 Pro 级别,但低于基础超人级别。

我已经编写了一些代码来测试它,但TOP 1过滤器似乎在JOIN之前应用,这意味着我总是看到最低等级而不是实际等级。任何人都可以帮我提出更好的选择吗?

SQL Fiddle here

代码在这里:

DECLARE @tbl_levels TABLE ([schemeID] int, [calevel] numeric(5,2), [desc] nvarchar(200))
DECLARE @level numeric(5,2) = 70
DECLARE @schemeID int = 1

insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 0, 'Newbie')
insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 25, 'Trainee')
insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 50, 'Moderate')
insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 75, 'Pro')
insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 100, 'Superman')

SELECT
    *
FROM
    (SELECT
        @level as [level],
        @schemeID as [schemeID]) ca LEFT OUTER JOIN 
    (SELECT 
        TOP 1 * 
    FROM 
        @tbl_levels
    ORDER BY 
        calevel ASC
    ) lvl ON lvl.schemeID = ca.schemeID AND lvl.calevel <= ca.[level]

4 个答案:

答案 0 :(得分:2)

SELECT @level as Level,s.*
from @tbl_levels s
where [calevel]=(Select Max([calevel]) from @tbl_levels where [calevel]<=@level)

作为对你的评论的回答

SELECT
    t.[level],
    (Select [desc] from @tbl_levels where [calevel]=(Select Max([calevel]) from @tbl_levels where [calevel]<=t.[level])) as [Desc]
FROM
    @test t

答案 1 :(得分:2)

您可以将问题重新定义为“匹配给定值的最高级别是多少?”然后解决方案变得明显。 70级是'中等':

SELECT TOP(1) @level, *
FROM @tbl_levels
WHERE [calevel] <= @level
ORDER BY calevel DESC;

对于多值,只需使用CROSS APPLY

SELECT
    t.[level],
    lvl.[desc]
FROM @test t 
cross apply (
select top(1) *
from @tbl_levels
where [calevel] <= [level]
order by calevel desc) as lvl;

答案 2 :(得分:1)

(更新)尝试:

;with r as 
(select l.*, row_number() over (partition by [schemeID] order by [calevel]) rn
 from @tbl_levels l),
cte as
(select l.*, n.[calevel] as [nextlevel]
 from r l 
 left join r n on l.[schemeID] = n.[schemeID] and l.rn+1 = n.rn)
SELECT
    ca.*, cte.[calevel],cte.[nextlevel],cte.[desc]
FROM @test ca 
LEFT OUTER JOIN cte
ON ca.schemeID = cte.schemeID AND 
   ca.[level] >= cte.[calevel] AND
   ca.[level] < coalesce(cte.[nextlevel], ca.[level]+1)

(SQLFiddle here

答案 3 :(得分:0)

DECLARE @tbl_levels TABLE ([schemeID] int, [calevel] numeric(5,2), [desc] nvarchar(200))
DECLARE @level numeric(5,2) = 70
DECLARE @schemeID int = 1

insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 0, 'Newbie')
insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 25, 'Trainee')
insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 50, 'Moderate')
insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 75, 'Pro')
insert into @tbl_levels ([schemeID],[calevel],[desc]) VALUES (1, 100, 'Superman')

SELECT
    TOP 1 *
FROM
    (SELECT
        @level as [level],
        @schemeID as [schemeID]) ca LEFT OUTER JOIN 
    (SELECT *
        FROM 
        @tbl_levels
    ) lvl ON lvl.schemeID = ca.schemeID AND lvl.calevel <= ca.[level]
    ORDER BY lvl.calevel DESC

拉​​吉