Вы можете использовать накопительную сумму для этого типа проблемы. Вот относительно простая реализация:
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;