次の [QueryMatch] サンプル データを考えてみましょう
InvoiceNumber RegionNumber Group
123 678 A
234 678 A
345 678 A
123 789 A
RegionNumberの値を (昇順で) 反復処理し、最小の InvoiceNumber を選択することもできますが、その方法は最終的に失敗します。InvoiceNumber 123 を RegionNumber 678 に割り当て、RegionNumber 789 を処理するときは、唯一可能な選択肢は InvoiceNumber 123 であり、それは既に使用されています。
したがって、RegionNumber 値のリストと、それぞれが持つ個別の InvoiceNumbers の数を取得することから始めることをお勧めします。これにより、最も制約のある RegionNumber 値を最初に処理できます。
SELECT qm.RegionNumber, Count(qm.InvoiceNumber) AS NumDistinctInvoiceNumbers
FROM
(
SELECT DISTINCT RegionNumber, InvoiceNumber FROM QueryMatch
) qm
GROUP BY qm.RegionNumber
ORDER BY 2 ASC
...戻ります...
RegionNumber NumDistinctInvoiceNumbers
789 1
678 3
...最初に RegionNumber 789 を処理し、次に「残り物」の 1 つを RegionNumber 678 に割り当てる必要があることがわかります。
ここで、特定の RegionNumber の未使用の InvoiceNumberの最小値を見つけるには、既に書き込み済みのものを除外する必要があります [表 2]。したがって、すでに InvoiceNumber 123 を RegionNumber 789 に「与えた」と仮定すると、RegionNumber 678 の適切な候補を見つける 1 つの方法は...
DMin("InvoiceNumber", "QueryMatch", "RegionNumber=678 AND InvoiceNumber NOT IN (Select InvoiceNumber FROM [Table 2])")
...最小の未使用の InvoiceNumber を返すかNull
、一致しない場合は返します。
それをいくつかの VBA コードでまとめると、次のようになります。
Public Sub AssignInvoicesToRegions()
Dim cdb As DAO.Database, rstRegion As DAO.Recordset, rst2 As DAO.Recordset
Dim vInvNo As Variant
Set cdb = CurrentDb
Set rst2 = cdb.OpenRecordset("Table 2", dbOpenDynaset)
Set rstRegion = cdb.OpenRecordset( _
"SELECT qm.RegionNumber, Count(qm.InvoiceNumber) AS NumDistinctInvoiceNumbers " & _
"FROM " & _
"( " & _
"SELECT DISTINCT RegionNumber, InvoiceNumber FROM QueryMatch " & _
") qm " & _
"GROUP BY qm.RegionNumber " & _
"ORDER BY 2 ASC", _
dbOpenSnapshot)
Do While Not rstRegion.EOF
Debug.Print rstRegion!RegionNumber
vInvNo = DMin("InvoiceNumber", "QueryMatch", "RegionNumber=" & rstRegion!RegionNumber & " " & _
"AND InvoiceNumber NOT IN (Select Nz(InvoiceNumber, 0) AS InvNo FROM [Table 2])")
If IsNull(vInvNo) Then
MsgBox "No available InvoiceNumber for RegionNumber=" & rstRegion!RegionNumber, _
vbCritical, "Lookup Failed"
Else
rst2.FindFirst "RegionNumber=" & rstRegion!RegionNumber
rst2.Edit
rst2!InvoiceNumber = vInvNo
rst2.Update
End If
rstRegion.MoveNext
Loop
Debug.Print "Done."
rstRegion.Close
Set rstRegion = Nothing
rst2.Close
Set rst2 = Nothing
Set cdb = Nothing
End Sub
現在の形式では、このアルゴリズムがすべての RegionNumber に一致することが保証されていないことに注意してください。RegionNumber 値が処理される順序によっては、すべての候補が取得されたことがわかる地域もあります (したがってIsNull()
、コードでのチェック)。その場合、アルゴリズムを微調整して、InvoiceNumber でこれらの地域に「最初のショット」を与える必要がある場合があります。おそらく、これらの「難しい」地域により高い優先度を手動で割り当てることによって可能です。