求和,然后在SQL中获得前70%的最小值和最大值

时间:2013-05-15 13:34:16

标签: sql sql-server

我有购买格式如下的产品的数据:

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 min / max列中的最低和最高价格。

我试图尽可能清楚,但如果这很难跟进,请告诉我哪些部分需要澄清。

注意:这些不是我的数据集中包含的唯一列,我也将选择并计算其他值。我只包括与此特定计算相关的列。

修改

到目前为止,这是我的代码,我需要将计算结合到此中(带有'@'符号的变量是用户给出的输入:

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

1 个答案:

答案 0 :(得分:2)

当某些事情超过阈值时,如何定义70%会有些含糊不清。然而,挑战是双重的。在确定累积比例后,查询还需要选择适当的行。这表示使用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