3

公平な配布の問題を解決するための効率的な SQL を考え出そうとしています。

私のデータ モデルは、1 つ以上の「ケース」を持つことができる「顧客」で構成されています。各顧客には、その顧客の世話をするために割り当てられた「ケース ハンドラー」が必要です。

私は、すべての「ケースハンドラー」が互いに可能な限り同じ量の「ケース」を持つように、すべての「ケースハンドラー」に「顧客」を分散しようとしています。

「顧客ID」と「ケース数」を取得するクエリがあります

例

現在合計 4 つのケース ハンドラーのテーブルがあります (ケース ハンドラーを追加または削除すると、このディストリビューションを再実行する必要があります)。

ケース ハンドラー テーブルと上記のクエリを結合する必要があることはわかっています。これにより、顧客ごとに更新を実行してケース ハンドラーを割り当てることができます。しかし、最も公平なマナーでケースのバランスをとるためにこれを行う方法についてはわかりません。

ほとんど機能する方法が 1 つあります。これは、ケース ハンドラの数によってクエリの行番号のモジュラスを使用して結合したため、ケース カウントで順番に並べられたクエリの各行を使用して、顧客をケースに割り当てることができます。ラウンドロビンのハンドラー。しかし、これでは公平な分配ができません。

(実際には、私のライブ システムの顧客テーブルは 100,000 を超えており、その大部分は 1 つのケースしかなく、2 つより少なく、3 つよりも少なく、51 件の顧客を持つ 1 人の顧客まであります)

誰でも私に与えることができる支援/アドバイスに感謝します。

4

2 に答える 2

0

ケースの分布はそれほど悪くありません。次のアプローチをお勧めします。

(1) お客様を 2 つのグループに分けます。. . 複数のケースと単一のケース。

(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、マルチプルとシングルトンという 2 つのグループの顧客をまとめることです。

于 2013-05-20T13:45:44.777 に答える