1

次のようにフォーマットされた製品の購入に関するデータがあります。

Item  |  Price  |  Quantity Bought

ABC      10.10     4
DEF      8.30      12
DEF      7.75      8
ABC      10.50     20
GHI      15.4      1
GHI      15.2      12
ABC      10.25     8
...      ...       ...

各行は、特定の金額を特定の価格で購入する個人を表します。このデータを集計し、テーブルから購入した合計数量の 30 パーセンタイル未満の価格を除外したいと考えています。

たとえば、上記のデータ セットでは、ABC が購入した製品の合計金額は (4+20+8) = 32 単位で、平均価格 = (4*10.10 + 8*10.25 + 20*10.50)/32 = 10.39 です。

上記のデータセットを次のように整理したいと思います。

Item  |  VWP   |  Total Vol  |  70th %ile min  |  70th %ile max
ABC      10.39    32            ???               ???
DEF      ...      20            ???               ???
GHI      ...      13            ???               ???

ここで、VWP は出来高加重価格で、70 番目の %ile min/max は出来高の上位 70% 内の最小価格と最大価格を表します。

言い換えれば、残りの価格にその日の総出来高の 70% が含まれるまで、最低出来高の価格を削除したいと考えています。次に、70 番目の %ile 最小/最大列に残っているものの最小価格と最大価格を公開したいと思います。

できるだけ明確にしようとしましたが、これを理解するのが難しい場合は、明確化が必要な部分を教えてください.

注: データセットに含まれる列はこれらだけではなく、他の値も選択して計算します。この特定の計算に関連する列のみを含めました。

編集:

これまでのコードは次のとおりです。これに計算を組み込む必要があります (変数の前に「@」記号が付いている変数は、ユーザーが指定した入力です。

SELECT Item, 
   SUM(quantity) AS Total_Vol, 
   DATEADD(day, -@DateOffset, CONVERT(date, GETDATE())) AS buyDate,
   MIN(Price) AS MinPrice,
   MAX(Price) AS MaxPrice,
   MAX(Price) - MIN(Price) AS PriceRange,
   ROUND(SUM(Price * quantity)/SUM(quantity), 6) AS VWP,

FROM TransactTracker..CustData
-- @DateOffset (Number of days data is offset by)
-- @StartTime (Time to start data in hours)
-- @EndTime (Time to stop data in hours)

WHERE DATEDIFF(day, TradeDateTime, GETDATE()) = (@DateOffset+1)
AND DATEPART(hh, TradeDateTime) >= @StartTime
AND HitTake = ''

OR DATEDIFF(day, TradeDateTime, GETDATE()) = @DateOffset
AND DATEPART(hh, TradeDateTime) < @EndTime
AND HitTake = ''

GROUP BY Item

編集2:

FROM (SELECT p.*,
(SELECT SUM(quantity) from TransactTracker..CustData p2 
    where p2.Series = p.Series and p2.Size >= p.Size) as volCum
FROM TransactTracker..CustData p
) p

編集3:

(case when CAST(qcum AS FLOAT) / SUM(quantity) <= 0.7 THEN MIN(Price) END) AS min70px,
(case when CAST(qcum AS FLOAT) / SUM(quantity) <= 0.7 THEN MAX(Price) END) AS max70px


FROM (select p.*,
  (select SUM(quantity) from TransactTracker..CustData p2 
  where p2.Item = p.Item and p2.quantity >= p.quantity) 
  as qcum from TransactTracker..CustData p) cd
4

1 に答える 1

3

何かがしきい値を超えたときに 70% を定義する方法には、あいまいな点があります。ただし、課題は 2 つあります。累積比率を特定した後、クエリは適切な行を選択する必要もあります。row_number()これは、選択に使用することを示唆しています。

SQL Server 2012 構文を使用するこのソリューションは、累積合計を計算します。次に、比率が 70% にどれだけ近いかに基づいて、連続した値を割り当てます。

select item,
       SUM(price * quantity) / SUM(quantity) as vwp,
       SUM(quantity) as total_vol,
       min(case when seqnum = 1 then price end) as min70price,
       max(case when seqnum = 1 then price end) as max70price
from (select p.*,
             ROW_NUMBER() over (partition by item order by abs(0.7 - qcum/qtot) as seqnum
      from (select p.*,
                   SUM(quantity) over (partition by item order by vol desc) as qcum,
                   SUM(quantity) over (partition by item) as qtot
            from purchases p
           ) p
     ) p
group by item;

70% 未満の最大値を取得するには、次のようにします。

max(case when qcum < qtot*0.7 then qcum end) over (partition by item) as lastqcum

そしてcase、外側の選択のステートメントは次のようになります。

min(case when lastqcum = qcum then price end) . . 

以前のバージョンの SQL Server では、相関サブクエリを使用して同じ効果を得ることができます。

select item,
       SUM(price * quantity) / SUM(quantity) as vwp,
       SUM(quantity) as total_vol,
       min(case when seqnum = 1 then price end) as min70price,
       max(case when seqnum = 1 then price end) as max70price
from (select p.*,
             ROW_NUMBER() over (partition by item order by abs(0.7 - qcum/qtot) as seqnum
      from (select p.*,
                   (select SUM(quantity) from purchases p2 where p2.item = p.item and p2.quantity >= p.quantity
                   ) as qsum,
                   SUM(quantity) over (partition by item) as qtot
            from purchases p
           ) p
     ) p
group by item

コードの例を次に示します。

SELECT Item, 
   SUM(quantity) AS Total_Vol, 
   DATEADD(day, -@DateOffset, CONVERT(date, GETDATE())) AS buyDate,
   MIN(Price) AS MinPrice,
   MAX(Price) AS MaxPrice,
   MAX(Price) - MIN(Price) AS PriceRange,
   ROUND(SUM(Price * quantity)/SUM(quantity), 6) AS VWP,
   min(case when seqnum = 1 then price end) as min70price,
   max(case when seqnum = 1 then price end) as max70price
from (select p.*,
             ROW_NUMBER() over (partition by item order by abs(0.7 - qcum/qtot) as seqnum
      from (select p.*,
                   (select SUM(quantity) from TransactTracker..CustData p2 where p2.item = p.item and p2.quantity >= p.quantity
                   ) as qsum,
                   SUM(quantity) over (partition by item) as qtot
            from purchases TransactTracker..CustData
           ) p
     ) cd
-- @DateOffset (Number of days data is offset by)
-- @StartTime (Time to start data in hours)
-- @EndTime (Time to stop data in hours)

WHERE DATEDIFF(day, TradeDateTime, GETDATE()) = (@DateOffset+1)
AND DATEPART(hh, TradeDateTime) >= @StartTime
AND HitTake = ''

OR DATEDIFF(day, TradeDateTime, GETDATE()) = @DateOffset
AND DATEPART(hh, TradeDateTime) < @EndTime
AND HitTake = ''

GROUP BY Item
于 2013-05-15T13:42:48.023 に答える