查找最接近列值的预设值

时间:2018-04-12 11:22:21

标签: sql sql-server validation

对于那些两次遇到这个问题的人;道歉。我试图使用不同的代码获得相同的答案;我还发布了这个以获取M,powerquery或excel解决方案。

我需要在整列的固定设定值中检索最接近的匹配值。

必须匹配的值集如下所示

| preceding column | Sys_size | 
===============================
| ...              |     null |
| ...              |        7 |
| ...              |        9 |
| ...              |       12 |
| ...              |       15 |
| ...              |       17 |
| ...              |     null |

所以简而言之,上面的列表是可变的(可以添加或更改更多的大小),并且包含空值。

其次,有一堆变量如下

| preceding column | User_size |
================================
| ...              |       8.5 |
| ...              |        13 |
| ...              |         6 |
| ...              |      10.5 |
| ...              |        18 |
| ...              |        14 |

我想在我的脚本中获得的结果如下所示

| preceding column | User_size | Sys_size |
===========================================
| ...              |       8.5 |        9 |
| ...              |        13 |       12 |
| ...              |         6 |        7 |
| ...              |      10.5 |       12 |
| ...              |        18 |       17 |
| ...              |        14 |       15 |

简单地说,它搜索与Sys_size输入匹配的最近的User_size。请注意,如果用户的值恰好落在两个Sys_size值之间,则会将结果四舍五入。

到目前为止,我已经实现了这个的反转版本,看起来与此类似,但仅适用于固定值输入:

SELECT DISTINCT Sys_Size
FROM System
WHERE ABS(Sys_Size - 8.5) = (
  SELECT MIN(ABS(Sys_Size - 8.5))
  FROM System
)

将返回9

但这必须系统地应用于整个用户专栏。我觉得我可笑地靠近并忽略了一些非常明显的东西。

2 个答案:

答案 0 :(得分:4)

在SQL Server中,您可以使用apply

select u.*, s.sys_size
from users u cross apply
     (select top (1) u.*
      from system s
      where s.sys_size is not null
      order by abs(s.sys_size - u.user_size)
     ) s;

答案 1 :(得分:1)

我知道的两个选项

declare @U table (s decimal(5,2));
declare @S table (s decimal(5,2));
insert into @U values (7), (9), (12), (15), (17); 
insert into @S values (8.5), (13), (6), (10.5), (18), (14); 

select u.s, ss.s 
from @U u
cross apply ( select top 1 s.s 
              from @S s 
              order by abs(u.s - s.s)
            ) ss;

select us, ss, diff 
from 
( select u.s as us, s.s as ss 
       , abs(s.s - u.s) as diff 
       , ROW_NUMBER() over (partition by u.s order by abs(s.s - u.s) asc) as rn
  from @U u
  cross join @S s 
  where u.s is not null and s.s is not null 
) tt
where tt.rn = 1
order by us, rn