首页 > 解决方案 > 存储桶中的数据分布 - Oracle 11g

问题描述

我有一个有两列的表BRANCHACTIVITIES其中BRANCH是位置的唯一 id,并且ACTIVITIES是属于各自的记录数BRANCH。这些记录将分布在 5 个存储桶中,所有存储桶都应包含几乎相等数量的记录。(无论差异是否为 +/-1000)

挑战是如果在一个桶中选择了一个分支,那么同一分支的所有活动也将在同一个桶中被选择,换句话说,属于一个的活动的数量BRANCH不能被拆分。让我们举一个非常简单的例子,这样我就可以解释我想要实现的目标

Total Branches=10
Total Number of activities (records) = 55,000
Average (total activities/total buckets) = 11,000

样本数据

在此处输入图像描述

分配后

在此处输入图像描述

所有存储桶都包含 11,000 条记录,但是当我们查看真实数据时,事情并不是那么简单。

请所有 Oracle 查询大师对此进行调查。您的专家意见将不胜感激。

标签: sqloracleoracle11g

解决方案


不幸的是,这是一个装箱问题,一个“完美”的解决方案需要——本质上——搜索所有可能的桶分配,然后选择“最好的”一个。而这样的方法并不真正适合 SQL。

但是,对于“足够好”的解决方案,类似循环方法的方法通常效果很好。只需从最大到最小枚举分支并将它们分配给存储桶:

select a.branch,
       1 + mod(seqnum, 5) as bucket
from (select a.branch, count(*) as cnt,
             row_number() over (order by count(*)) desc as seqnum
      from activities a
      group by a.branch
     ) a;

由于排序,这通常会创建不同大小的桶。因此,稍有变化将桶分配为 1-2-3-4-5-5-4-3-2-1:

select a.branch,
       (case when mod(seqnum, 10) in (0, 9) then 1
             when mod(seqnum, 10) in (1, 8) then 2
             when mod(seqnum, 10) in (2, 7) then 3
             when mod(seqnum, 10) in (3, 6) then 4
             when mod(seqnum, 10) in (4, 5) then 5
        end) as bucket
from (select a.branch, count(*) as cnt,
             row_number() over (order by count(*)) desc as seqnum
      from activities a
      group by a.branch
     ) a;

推荐阅读