簡體   English   中英

SQL 獲取最接近數字的值

[英]SQL Get closest value to a number

我需要從 Quantity 列中找到 Divide 列中每個數字的最接近的值,並將在這兩個 Quantities 的 Value 列中找到的值。

示例:在 Divide 列中,5166 的值將最接近 Quantity 列的值 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

這里有幾個答案,但它們都使用 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

如果我理解要求, 5166並不最接近5000 - 它接近525016684的增量)

相應的查詢,沒有循環,應該是(這里的小提琴: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=be434e67ba73addba119894a98657f17 )。

(我添加了一個Value_Rank ,因為不確定您是否希望保留或重新計算Rank

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

或者,如果最接近你的意思是以前最接近的(這里的小提琴: https://dbfiddle.uk/?rdbms=sqlserver_2017&fiddle=b41fb1a3fc11039c7f82926f8816e270 )。

select
    Quantity, Divide, Rank, Value,
    dense_rank() over(order by Value) as Value_Rank
from
    (
        select
            so.Quantity, so.Divide, so.Rank,
            -- There is no LessEqualThan, assume 0
            max(isnull(so_let.Quantity, 0)) as Value
        from
            SO so
                left outer join SO so_let
                on so_let.Quantity <= so.Divide
        group by so.Quantity, so.Divide, so.Rank
    ) result

您不需要循環,基本上您需要找到除數和所有數量(第一個 cte)之間的最小差異。 然后用這個距離找到對應的記錄(第二個cte)然后和你的初始表join得到轉換后的值(最終選擇)

;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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM