Создание скалярной функции, которая принимает входные данные и ранжирует цены за единицу в порядке убывания - PullRequest
2 голосов
/ 07 апреля 2020

Мне трудно разработать правильную скалярную функцию для работы, как задумано. Требуется ввести тип денег. У меня есть таблица продуктов с колонкой UnitPrice, на которой я сосредоточен. Мне нужна моя функция для сортировки товаров в порядке убывания цен за единицу, причем наибольшая цена имеет ранг 1, следующий ранг 2 и т.д. c. Одинаковые цены должны ранжироваться одинаково, а ранговые номера должны назначаться последовательно и непрерывно, не пропуская и не перепрыгивая никакие числа. То есть ранги должны выглядеть как 1, 2, 3, 4, 5, ......, 61 и 62. Тогда моя функция найдет ранг продукта (ов), цена за единицу которого равна входу денежное значение и вернуть ранг номер. Если входная денежная стоимость не существует в таблице «Продукты», она возвращает -1. Например, поскольку существует четыре продукта с ценой за единицу, равной 18 долларам, и все они ранжируются как 40, RankOfGivenPrice (18) должен возвращать 40. Поскольку ни один из продуктов не имеет цену за единицу в 5 долларов США, RankOfGivenPrice (5) возвращает -1.

Моя попытка:

    go
create function RankOfGivenPrice
    (@unitprice money)
    returns money
begin
return
    (select TOP 1
    rank() over(order by UnitPrice desc) as RankNum
    from Products
    where UnitPrice = @unitprice)
end
go

Это может скомпилировать, но это не дает нужного мне результата. Я вызываю функцию вроде select dbo.RankOfGivenPrice (18), но она возвращает 1.00. Если я не использую TOP 1, я получаю «Подзапрос вернул более 1 значения». ошибка при вызове функции. Я предполагаю, что должен использовать функцию RANK (), но это трудно с подзапросом.

Ответы [ 3 ]

0 голосов
/ 07 апреля 2020

Вместо этого используйте эту логику c:

 select count(*) + 1 as RankNum
 from Products
 where UnitPrice > @unitprice

Для этого вам не нужна функция rank().

Здесь - это дБ <> скрипка.

0 голосов
/ 13 апреля 2020

Вы можете использовать dense_rank() вместо rank Вы можете узнать больше о функции и как она работает здесь

На примере GMB функция будет выглядеть следующим образом.

GO
CREATE FUNCTION RankOfGivenPrice
    (@unitprice money)
    returns money
BEGIN
return
    (
        SELECT max(case when UnitPrice = @unitprice then Price_Rank else -1 end)
        FROM (
            SELECT UnitPrice, dense_rank() over (order by UnitPrice desc) as Price_Rank
            FROM Products
        )t

    )
END
GO
0 голосов
/ 07 апреля 2020

Сначала вам нужно получить ранжирование в подзапросе, , а затем фильтр по параметру:

create function RankOfGivenPrice
    (@unitprice money)
    returns money
begin
return
    (
        select RankNum
        from (
            select UnitPrice, rank() over(order by UnitPrice desc) as RankNum
            from Products
        ) t
        where UnitPrice = @unitprice
    )
end

Скорее всего, вам не нужно TOP 1 во внешнем запросе, если более одной цены не соответствует @unitprice. В этом случае вы также можете использовать агрегатную функцию, такую ​​как min() или max(), например:

return
    (
        select max(RankNum)
        from (
            select UnitPrice, rank() over(order by UnitPrice desc) as RankNum
            from Products
        ) t
        where UnitPrice = @unitprice
    )

Если вы хотите -1 для пропущенных значений:

return
    (
        select max(case when UnitPrice = @unitPrice then RankNum else -1 end)
        from (
            select UnitPrice, rank() over(order by UnitPrice desc) as RankNum
            from Products
        ) t
    )
...