1

I want to create the following in SQL Server 2012: (I've found that the best way to explain it is with tables).

I have the date of purchase, the customer id and the price the customer paid in a table like this:

DateOnly     Customer    Price
2012/01/01      1         50
2012/01/01      2         60      
2012/01/01      3         80
2012/01/02      4         40
2012/01/02      5         30
2012/01/02      1         55
2012/01/03      6         80
2012/01/04      2         90

What I need to do then is to keep a register of the average price paid by a customer. Which would be as follows:

DateOnly     Customer    Price    AveragePrice
2012/01/01      1         50           50
2012/01/01      2         60           60
2012/01/01      3         80           80
2012/01/02      4         40           40
2012/01/02      5         30           30
2012/01/02      1         55          52.5
2012/01/03      6         80           80 
2012/01/04      2         90           75

And finally, I need to select the rows which have caused an increase higher than 10% in the averageprice paid by a customer.

In this case, the second order of customer 2 should be the only one to be selected, as it introduced an increase higher than 10% in the average price paid by this customer.

Hence, the resulting table should be as follows:

DateOnly     Customer    Price    AveragePrice
2012/01/04      2         90           75

Thanks in advance for your help.

4

2 回答 2

1

首先 CTE 是准备您的数据 = 将 row_numbers 分配给每个客户的购买,以便进一步用于连接。

第二个 CTE 是递归的,它完成了所有正在进行的工作。第一部分是获取每个客户的第一次购买,递归部分在下一次购买时加入并计算 TotalPrice、AveragePrice 和 increase。

最后只需选择增加超过 10% 的行。

WITH CTE_Prep AS 
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY Customer ORDER BY DateOnly) RN
    FROM Table1
)
,CTE_Calc AS
(
    SELECT *, Price AS TotalPrice, CAST(Price AS DECIMAL(18,2)) AS AveragePrice, CAST (0 AS DECIMAL(18,2)) AS Increase 
    FROM CTE_Prep WHERE RN = 1

    UNION ALL

    SELECT p.*
        , c.TotalPrice + p.Price AS TotalPrice 
        , CAST(CAST(c.TotalPrice + p.Price AS DECIMAL(18,2)) / p.RN AS DECIMAL(18,2)) AS AveragePrice
        , CAST(CAST(CAST(c.TotalPrice + p.Price AS DECIMAL(18,2)) / p.RN AS DECIMAL(18,2)) / c.AveragePrice AS DECIMAL(18,2)) AS Increase
    FROM CTE_Calc c
    INNER JOIN CTE_Prep p ON c.RN + 1 = p.RN  AND p.Customer = c.Customer
)
SELECT * FROM CTE_Calc
WHERE Increase > 1.10

SQLFiddle 演示

于 2013-07-29T14:55:55.423 回答
1

有趣的问题。

您可以通过从该行的所有价格总和中减去每行的价格来获得没有当前购买的平均值。这个观察 - 结合窗口函数 - 提供了获取您正在寻找的行所需的信息:

select *
from (select t.*,
             avg(price) over (partition by customer) as avgprice,
             sum(price) over (partition by customer) as sumprice,
             count(price) over (partition by customer) as cntprice
      from table1 t
     ) t
where (case when cntprice > 1
            then (sumprice - price) / (cntprice - 1) 
       end) > avgprice*1.1;

注意子句case中的使用。where存在潜在的除以零问题。SQL Server 保证when案例的部分将在then部分(在情境中)之前进行评估。所以这个问题是安全的。

于 2013-07-29T14:40:18.820 回答