TSQL-基于重量的多个位置的随机赢家

时间:2018-11-01 17:24:19

标签: sql-server tsql sql-server-2008 random

我们公司每个月都会为“当月客户”绘制图纸。该图基本上是基于客户当月花费多少的加权图。

目前,我正在获取客户名称及其积分数量,并通过我在网上找到的Excel随机分配器对其进行运行。每月在40多个位置单独进行操作变得很麻烦。

我要道歉,因为我已经看到了其他一些问题,但是我不能全神贯注地编写TSQL来选择随机加权获胜者。

如果单个命令可以向我输出每个位置的随机获胜者,那就太好了,但是我很难找到从哪里开始并确保正确选择加权获胜者。

Base Query with Results:

期望的结果只是获奖者名单,每个地点一个。

1 个答案:

答案 0 :(得分:0)

您可以使用累积总和来解决此类问题。这是一个相对简单的实现:

select t.*
from (select locationId, customerId, sum(sales) as sumSales,
             sum(sum(sales)) over (partition by locationId) as total_sales,
             (sum(sum(sales)) over (partition by locationId order by newid()) * 1.0 / sum(sum(sales)) over (partition by locationId)) as cumulative_ratio
      from t
      where salesdate between ? and ?  -- whatever your range
      group by locationId, customerId
     ) t
where 0.5 >= cumulative_ratio - sumSales * 1.0 / total_sales and
      0.5 < cumulative_ratio;

您可以看到它在做什么。假设您在一个地点有4个客户:

l    c    s
1    A    1
1    B    2
1    C    3
1    D    4

然后将数据扩充为:

l    c    s    total_sales  cumulative ratio
1    A    1        10             0.1    
1    B    2        10             0.3 
1    C    3        10             0.7
1    D    4        10             1.0

最后的WHERE选择累积比率和前一个值之间的0.5。它是通过从比率中减去当前行数据来实现的。

此示例显示了按字母顺序订购的客户。但是,查询将它们随机排序。 0.5是完全,完全任意的。任何值都可以,因为随机性已经内置在累积比率中。

编辑:

A,这在SQL Server 2008上不起作用。我们可以使用apply来解决此问题,尽管代码的效率甚至更低:

with sales as (
      select locationId, customerId, sum(sales) as sumSales, newid() as random
      from t
      where salesdate between ? and ?  -- whatever your range
      group by locationId, customerId
     )
select t.*
from (select locationId, customerId, sum(sales) as sumSales,
             ss.runningsumsales,
             sum(sum(sales)) over (partition by locationId) as totalsales
      from sales s cross apply
           (select sum(s2.sumsales) as runningsumsales
            from sales s2
            where s2.locationId = s.locationId and s2.random <= s.random
           ) ss
      where salesdate between ? and ?  -- whatever your range
      group by locationId, customerId
     ) t
where 0.5 >= (runningsumsales - sumSales) * 1.0 / total_sales and
      0.5 < runningsumsales / total_sales;