我有购买格式如下的产品的数据:
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
答案 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