2

私はこれに似たデータを持っています:

Price   DateChanged   Product
10       2012-01-01   A
12       2012-02-01   A
30       2012-03-01   A
10       2012-09-01   A
12       2013-01-01   A
110      2012-01-01   B
112      2012-02-01   B
130      2012-03-01   B
110      2012-09-01   B
112      2013-01-01   B

平均値を計算したいのですが、課題は次のとおりです。最初のレコードを見ると、価格10は1か月間有効、価格12は1か月間有効、価格30は6期間有効です。数ヶ月。

したがって、製品A(10 + 12 + 30 + 10 + 12)/ 5の基本平均は、期間を考慮に入れて14.8になり、平均価格は約20.1になります。

これを解決するための最良のアプローチは何ですか?期間を計算するために結合するrow_number()を使用してサブクエリを作成できることは知っていますが、より良い方法はありますか?SQL ServerにはSTDistanceのような強力な機能があるので、確かにこのための機能はありますか?

4

2 に答える 2

2

あなたが探しているのはweighted averageと呼ばれ、私の知る限り、SQL Server にはそれを計算する組み込み関数はありません。とはいえ、手で計算するのはそれほど難しいことではありません。

まず、各データ ポイントの重みを見つける必要があります。この場合、各価格期間の期間を見つける必要があります。簡単に検索できる列をデータに追加することもできますが、次のようにすることもできます。

SELECT p1.Product, p1.Price, p1.DateChanged AS DateStart,
       isnull(min(p2.DateChanged),getdate()) AS DateEnd
INTO #PricePlanStartEnd
FROM PricePlan p1
  LEFT OUTER JOIN PricePlan p2
    ON p1.DateChanged < p2.DateChanged
    AND p1.Product =p2.Product
GROUP BY p1.Product, p1.Price, p1.DateChanged
ORDER BY p1.Product, p1.DateChanged

これにより、#PricePlanStartEnd各価格期間の開始と終了を含む一時テーブルが作成されます。現在の期間の終わりとして getdate() を使用しました。最後の価格変動までの平均を計算する必要がある場合INNER JOINは、LEFT OUTER JOIN.

その後、(価格 * 期間) の合計を期間の合計の長さで割り、答えを得る必要があります。

ここに計算のSQLフィドルがあります

また、月を操作するときは、すべての月が同じであるとは限らないことを覚えておく必要があります。そのため、12 月の価格は 2 月よりも長くアクティブでした。

于 2013-02-04T10:32:46.963 に答える
1

CTEとを使用して、最後のrow_number()までの月平均を取得します。フィドルデモ dateChanged

;with cte as (
   select product, dateChanged, price, 
          row_number() over (partition by product order by datechanged) rn
   from x
)
select t1.product, 
sum(t1.price *1.0 * datediff(month, t1.dateChanged,t2.dateChanged))/12 monthlyAvg
from cte t1  join cte t2 on t1.product = t2.product
                         and t1.rn +1 = t2.rn
group by t1.product

--Results
Product MonthlyAvg
A       20.166666
B       120.166666

または、最新の毎日の平均が必要な場合は、LEFT JOIN Fiddle-Demoを使用してください。

;with cte as (
    select product, dateChanged, price, 
       row_number() over (partition by product order by datechanged) rn
    from x
)
select t1.product, 
sum(t1.price *1.0 * 
   datediff(day, t1.dateChanged,isnull(t2.dateChanged,getdate())))/365 dailyAvg
from cte t1 left join cte t2 on t1.product = t2.product
and t1.rn +1 = t2.rn
group by t1.product

--Results
product dailyAvg
A       21.386301
B       130.975342
于 2013-02-04T10:20:02.263 に答える