让我们考虑以下 [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 值的列表以及每个具有的不同 InvoiceNumber 的数量开始。这将使我们首先处理最受约束的 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,然后将其中一个“剩余”分配给 RegionNumber 678。
Now, to find the lowest unused InvoiceNumber for a given RegionNumber we need to exclude any ones that we have already written to [Table 2]. So, assuming that we have already "given" InvoiceNumber 123 to RegionNumber 789, one way to find a suitable candidate for RegionNumber 678 would be...
DMin("InvoiceNumber", "QueryMatch", "RegionNumber=678 AND InvoiceNumber NOT IN (Select InvoiceNumber FROM [Table 2])")
...which will return the smallest unused InvoiceNumber, or Null
if not match is found.
Wrap that up in some VBA code and we get
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
Note that in its current form this algorithm is not guaranteed to find a match for every RegionNumber. Depending on the order in which the RegionNumber values are processed some regions may find that all of their candidates have been taken (hence the IsNull()
check in the code). In that case you may have to tweak the algorithm to give those regions "first shot" at an InvoiceNumber, possibly by manually assigning a higher priority to those "difficult" regions.