TSQL Выберите строку Min & Max при группировании

Допустим, у меня есть таблица, содержащая много-много таких строк:

ID        Range         Range_begining        Profit
----------------------------------------------------
 1    (100-150)                    100           -20
 2    (200-250)                    200          40.2
 3    (100-150)                    100           100
 4    (450-500)                    450           -90
...

Я делаю такой простой запрос:

SELECT max([Range]) AS 'Range'
    , count(ID) AS 'Count'
    , round(avg([Profit]), 2) AS 'AVG Profit'
    FROM
        Orders
    GROUP BY
        Range_begining

После выполнения этого запроса я получаю такие результаты:

Range        Count        AVG Profit
------------------------------------
(100-150)        2                40
(200-250)        1              40.2
(450-500)        1               -90
...

Довольно просто:)

Теперь мне нужно выбрать строку с минимальной и максимальной прибылью, где количество больше 10 (это параметр)

Я смог получить минимальное значение с этим:

SELECT TOP 1 [Range], [AVG Profit] FROM (
     SELECT max([Range]) AS 'Range'
        , count(ID) AS 'Count'
        , round(avg([Profit]), 2) AS 'AVG Profit'
        FROM
            Orders
        GROUP BY
            Range_begining) X
WHERE
    [Count]>10
ORDER BY 
    [AVG Profit] ASC --or DESC if I want max profit

Я думал сделать UNIONдля вышеуказанного запроса с помощью ORDER BY DESC, но это не лучшее решение.

Что мне нужно сделать:
Выберите 2 строки :одну с минимальной, вторую с максимальной AVG Profit при группировке по диапазону.

РЕДАКТИРОВАТЬ: Если я добавлю 2 столбца перемещения в свою основную таблицу данных, например:

ID        Range         Range_begining        Profit        OrderDate     Company
---------------------------------------------------------------------------------
 1    (100-150)                    100           -20        2012-01-02          1
 2    (200-250)                    200          40.2        2012-03-22          0
 3    (100-150)                    100           100        2012-02-05          0
 4    (450-500)                    450           -90        2012-05-12          1
...

А затем попробуйте добавить еще 2 таких условия:

; with ordering as (
  SELECT max([Range]) AS 'Range'
    , count(ID) AS 'Count'
    , round(avg([Profit]), 2) AS 'AVG Profit'
    , row_number() over (order by avg([Profit])) rn_min
    , row_number() over (order by avg([Profit]) desc) rn_max
    FROM
        Orders
    GROUP BY
        Range_begining
    HAVING COUNT(ID) > 10
    AND [Company]=@company
    AND (@from= '' OR [OrderDate]>=@from)
    AND (@to= '' OR [OrderDate]<=@to)
)
select [range], [count], [avg profit]
  from ordering
 where (rn_max = 1 or rn_min = 1)

Я получаю сообщение об ошибке, потому что [Компания] и [Дата заказа]

is invalid in the HAVING clause because it is not contained in either an aggregate function or the GROUP BY clause.

Как я могу это исправить?

РЕДАКТИРОВАТЬ2 Получил работу!

; with ordering as (
  SELECT max([Range]) AS 'Range'
    , count(ID) AS 'Count'
    , round(avg([Profit]), 2) AS 'AVG Profit'
    , row_number() over (order by avg([Profit])) rn_min
    , row_number() over (order by avg([Profit]) desc) rn_max
    FROM
        Orders
    WHERE
    [Company]=@company
    AND (@from= '' OR [OrderDate]>=@from)
    AND (@to= '' OR [OrderDate]<=@to)
    GROUP BY
        Range_begining
    HAVING COUNT(ID) > 10
)
select [range], [count], [avg profit]
  from ordering
 where (rn_max = 1 or rn_min = 1)

РЕДАКТИРОВАТЬ 3 Могу ли я вернуть еще один столбец с таким описанием:

Range        AVG Profit               Description
-------------------------------------------------
(200-250)          40.2           Max profit here
(450-500)           -90     Min profit, well done

РЕДАКТИРОВАТЬ 4 Быстрый ответ (на основе ответа @Nikola Markovinović):

; with ordering as (
  SELECT max([Range]) AS 'Range'
    , count(ID) AS 'Count'
    , round(avg([Profit]), 2) AS 'AVG Profit'
    , row_number() over (order by avg([Profit])) rn_min
    , row_number() over (order by avg([Profit]) desc) rn_max
    FROM
        Orders
    WHERE
    [Company]=@company
    AND (@from= '' OR [OrderDate]>=@from)
    AND (@to= '' OR [OrderDate]<=@to)
    GROUP BY
        Range_begining
    HAVING COUNT(ID) > 10
)
    SELECT
    CASE WHEN rn_max=1 THEN 'This is max' ELSE 'Min' END AS 'Description'
   ,[range]
   ,[count]
   ,[avg profit]
    FROM ordering
    WHERE (rn_max = 1 or rn_min = 1)
5
задан Misiu 17 August 2012 в 09:51
поделиться