SQL Получить ближайшее значение к числу - PullRequest
0 голосов
/ 20 сентября 2019

Мне нужно найти закрытое значение каждого числа в столбце Делить из столбца Количество и поместить значение, найденное в столбце Значение для обоих количеств.

Пример: В столбце Разделить значение 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 ]

2 голосов
/ 20 сентября 2019

Здесь есть несколько ответов, но они оба используют ctes / complex subqueries.Существует гораздо более простой / быстрый способ, просто сделав пару самостоятельных соединений и сгруппировав их по

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 голос
/ 20 сентября 2019

Если я понял требования, 5166 - это , а не , ближайший к 5000 - он закрывается к 5250 (дельта 166 против 84)

.соответствующий запрос, без циклов, должен быть (скрипеть здесь: 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
0 голосов
/ 20 сентября 2019

Вам не нужен цикл, в основном вам нужно найти наименьшую разницу между делением и всеми величинами (первое 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...