6

このような多くの行を含むテーブルがあるとしましょう。

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

ORDER BY DESCを使用して上記のクエリを実行することを考えていましたUNIONが、これは最善の解決策ではありません。

私がする必要があること:
2つの行を選択します。1つは最小、2つ目は最大のAVG利益で、範囲でグループ化します。

編集: 次のようにメインデータテーブルに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)

[Company]と[OrderDate]が原因でエラーが発生します

集計関数にもGROUPBY句にも含まれていないため、HAVING句では無効です。

どうすればこれを修正できますか?

EDIT2 動作しました!

; 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 速い答え(@NikolaMarkovinovićの答えに基づく):

; 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)
4

2 に答える 2

7

あなたはウィンドウ関数を使って一度にそれをするかもしれません:

; 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
)
select [range], [count], [avg profit],
       case when rn_max = 1 
            then 'Max profit'
            else 'Min profit'
        end Description
  from ordering
 where (rn_max = 1 or rn_min = 1)

そして、これがSqlFiddleの例です。

于 2012-08-17T08:14:17.973 に答える
2

これがSQLFiddleの例です。最後の質問クエリでは、ネストされたクエリの代わりにHAVINGを使用できます。

select * from
(SELECT TOP 1
    max([Range]) AS 'Range'
     , count(ID) AS 'Count'
     , round(avg([Profit]), 2) AS 'AVG Profit'
    FROM
        Orders
    GROUP BY
        Range_begining
    having count(id)>10
    order by round(avg([Profit]), 2) ASC
) a
union all
select * from 
(
SELECT TOP 1
    max([Range]) AS 'Range'
     , count(ID) AS 'Count'
     , round(avg([Profit]), 2) AS 'AVG Profit'
    FROM
        Orders
    GROUP BY
        Range_begining
    having count(id)>10
    order by round(avg([Profit]), 2) desc
)b
于 2012-08-17T08:02:25.310 に答える