SQL取得最接近数值的值

时间:2019-09-20 01:19:11

标签: sql sql-server

我需要在“数量”列中的“划分”列中找到每个数字的壁橱值,并将找到的值放入两个数量的“值”列中。

示例: 在“划分”列中,值5166将最接近“数量”列值5000。为避免多次使用这两个值,我需要将这两个数字的值5000放置在值列中,如下例所示。另外,是否可以不进行循环操作?

Quantity    Divide  Rank         Value
15500       5166    5            5000
1250        416     5            0
5000        1666    5            5000
12500       4166    4            0
164250      54750   3            0
5250        1750    3            0
6250        2083    3            0
12250       4083    3            0
1750        583     2            0
17000       5666    2            0
2500        833     2            0
11500       3833    2            0
1250        416     1            0

3 个答案:

答案 0 :(得分:2)

这里有两个答案,但是它们都使用ctes / complex子查询。通过执行几次自我连接和分组,可以有一种更简单/更快的方法

https://www.db-fiddle.com/f/rM268EYMWuK7yQT3gwSbGE/0

select 
      min(min.quantity) as minQuantityOverDivide
    , t1.divide
    , max(max.quantity) as maxQuantityUnderDivide
    , case 
        when 
            (abs(t1.divide - coalesce(min(min.quantity),0)) 
            <
            abs(t1.divide - coalesce(max(max.quantity),0)))
        then max(max.quantity)
        else min(min.quantity) end as cloestQuantity

from t1
left join (select quantity from t1) min on min.quantity >= t1.divide
left join (select quantity from t1) max on max.quantity < t1.divide

group by    
    t1.divide

答案 1 :(得分:1)

如果我理解这些要求,那么51665000的距离不是-与5250接近(166与{{ 1}})

(不带循环)对应的查询应为(在此处为https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=be434e67ba73addba119894a98657f17)。

(我添加了84,因为不确定是否要保留或重新计算Value_Rank

Rank

或者,如果最近,则表示上一个最接近的(此处为小提琴:https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b41fb1a3fc11039c7f82926f8816e270)。

select
    Quantity, Divide, Rank, Value,
    dense_rank() over(order by Value) as Value_Rank
from
    (
        select
            Quantity, Divide, Rank,
            --
            case
                when abs(Quantity_let_delta) < abs(Quantity_get_delta) then Divide + Quantity_let_delta
                                                                       else Divide + Quantity_get_delta
            end as Value
        from
        (
            select
                so.Quantity, so.Divide, so.Rank,
                -- There is no LessEqualThan, assume GreaterEqualThan
                max(isnull(so_let.Quantity, so_get.Quantity)) - so.Divide as Quantity_let_delta,
                -- There is no GreaterEqualThan, assume LessEqualThan
                min(isnull(so_get.Quantity, so_let.Quantity)) - so.Divide as Quantity_get_delta
            from
                SO so
                    left outer join SO so_let
                    on so_let.Quantity <= so.Divide
                    --
                    left outer join SO so_get
                    on so_get.Quantity >= so.Divide
            group by so.Quantity, so.Divide, so.Rank
        ) so
    ) result

答案 2 :(得分:0)

您不需要循环,基本上您需要找到除法和所有数量(第一个cte)之间的最小差异。然后使用此距离查找相应的记录(第二个cte),然后与初始表连接以获取转换后的值(最终选择)

;with cte as (
select t.Divide, min(abs(t2.Quantity-t.Divide)) as ClosestQuantity
from #t1 as t
    cross apply #t1 as t2
group by t.Divide
)
,cte2 as (
select distinct
    t.Divide, t2.Quantity
from #t1 as t
cross apply #t1 as t2
where abs(t2.Quantity-t.Divide) = (select ClosestQuantity from cte as c where c.Divide = t.Divide)
)
select t.Quantity, cte2.Quantity as Divide, t.Rank, t.Value
from #t1 as t
left outer join cte2 on t.Divide = cte2.Divide