TSQL - случайный победитель для нескольких локаций в зависимости от веса - PullRequest
0 голосов
/ 01 ноября 2018

Наша компания каждый месяц проводит розыгрыш «Заказчик месяца». Чертеж в основном представляет собой взвешенный чертеж, основанный на том, сколько клиент потратил в этом месяце.

В настоящее время я получаю имя клиента и его количество баллов и запускаю его через рандомизатор Excel, который я нашел в Интернете. Это становится громоздким, делая это индивидуально для 40+ мест каждый месяц.

Я собираюсь извиниться, потому что я видел некоторые другие вопросы по этому поводу, но я просто не могу обернуться, написав TSQL, чтобы выбрать случайного взвешенного победителя.

Очевидно, было бы неплохо, если бы одна команда могла выдать мне случайного победителя для каждой локации, но у меня возникли трудности с поиском, с чего начать, и с обеспечением правильного выбора взвешенного победителя.

Base Query with Results:

Желаемым результатом будет список победителей, по одному на каждое местоположение.

1 Ответ

0 голосов
/ 01 ноября 2018

Вы можете использовать накопительную сумму для этого типа проблемы. Вот относительно простая реализация:

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 полностью, полностью произвольно. Подойдет любое значение, потому что случайность уже встроена в совокупное отношение.

EDIT:

Увы, это не работает в 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;
...