3

我正在尝试提出一个有效的 sql 来解决公平分配问题。

我的数据模型由一个“客户”组成,它可以有 1 个以上的“案例”。每个客户都需要一个“案件处理人员”,负责照顾该客户。

我正在尝试将“客户”分配给所有“案例处理者”,以使所有“案例处理者”彼此之间的“案例”数量尽可能接近。

我有一个查询,它给了我一个“客户 ID”和“案例计数”

例子

我有一个案例处理程序表,我目前总共有 4 个(可以添加或删除案例处理程序,然后必须重新运行此分发)。

我知道我需要对 case handlers 表和上面的查询进行连接,这样我就可以为每个客户执行更新以为他们分配一个 case handlers。但我不知道如何在最公平的庄园中平衡案件。

我有一种几乎可行的方法是我通过案例处理程序的计数使用查询的行号上的模数加入,因此查询中按案例计数顺序排序的每一行然后可以用于将客户分配给案例循环赛的处理程序。但这并没有给出公平的分配。

(实际上,我的实时系统中的客户表超过 100,000,其中大多数只有一个案例,少于 2 个,甚至更少,有 3 个等等,最多一个客户有 51 个案例)

感谢任何人都可以给我的任何帮助/建议。

4

2 回答 2

1

有一些正式的优化框架可以解决这类问题,但我认为你可以用更简单的方法来解决问题。根据您的描述,听起来每个客户只能有一个案件处理人员,所以有些不幸的人需要处理您最大客户的所有 51 个案件。

尝试这样的事情(伪代码):

total_cases = SUM(Case_Count)
total_handlers = COUNT(Case_Handlers)

foreach SELECT Customer_Id, Case_Count ORDER BY Case_Count DESCENDING:

   # Calculate the target number of cases to assign to the next handler
   target_cases_per_handler = total_cases / total_handlers

   # If a customer has more than the target number of cases, then
   # it must be assigned to a case handler
   if Case_Count > target_cases_per_handler:
       assign_to_handler(Customer_Id)
       total_handlers = total_handlers - 1
       total_cases = total_cases - Case_Count

   # Otherwise, try to pair up the cases with a small number of cases
   # that is close to average (this part is inefficient)
   else:
       assign_to_handler(Customer_Id)
       residual = CEIL(target_cases_per_handler - Case_Count)
       while (residual > 0)
           best_customer_id, best_case_count = SELECT TOP 1 Customer_Id, Case_Count ORDER BY ABS(Case_Count - residual) ASCENDING

           assign_to_handler(best_customer)
           residual = residual - best_case_count
           total_cases = total_cases - best_case_count

       total_handlers = total_handlers - 1

这应该让您粗略地将客户分配给案例处理程序,同时仍确保每个客户都有一个处理程序。

于 2013-05-20T13:32:32.407 回答
0

你的病例分布还不错。我会推荐以下方法:

(1) 将顾客分成两组。. . 多案和单案。

(2) 以循环方式将多个案例分配给案例工作者。

(3) 将单个案例分配给个案工作者,以平衡每个个案工作者。

这将适用于您的特定发行版(主要是单例)。它不一定是通用算法。

这是SQL:

with multiples as (
      select CustomerId, COUNT(*) CaseCnt,
             ROW_NUMBER() over (partition by CustomerId order by CustomerId) % @NumHandlers as theHandler
      from customers c
      group by CustomerId
      having COUNT(*) > 1
     ),
    h as (
     select theHandler, SUM(CaseCnt) as CaseCnt,
            SUM(CaseCnt) - (NumCusts / @NumHandlers) as StillNeeded
     from multiples cross join
          (select COUNT(*) as NumCusts from customers c) const
     group by theHandler
    ),
    hsum as (
     select h.*, SUM(StillNeeded) over (order by StillNeeded) as endnum,
            SUM(StillNeeded) over (order by StillNeeded) - StillNeeded + 1 as startnum
     from h
    ),
    singles as (
     select CustomerId, ROW_NUMBER() over (partition by CustomerId order by CustomerId) as seqnum
     from Customers
     group by CustomerId
     having COUNT(*) = 1
    ),
    singlesh as (
     select singles.Customerid, h.theHandler
     from singles join
          hsum
          on singles.seqnum between h.startnum and h.endnum
   )
select *
from ((select CustomerId, theHandler
       from multiples
      ) union all
      (select CustomerId, theHandler
       from singlesh
      )
     ) t

SQL 几乎遵循上面的解释。它首先以循环方式将多条记录随机分配给处理程序。处理程序只是从 0 到 @NumHandlers 的数字。然后它计算“StillNeeded”案例的数量以达到最大值。注意:这假设处理程序的数量是客户数量的精确倍数。修复的调整使查询看起来更复杂。

然后它计算仍然需要为每个处理程序填写的数字。关键是将其作为累积和(这使用 SQL Server 2012 语法,在早期版本中,您使用相关子查询来执行此操作)。然后使用此信息将单例分配给每个处理程序。

最后一步是把union两组客户放在一起,即多个客户和单身客户。

于 2013-05-20T13:45:44.777 回答