访问查询匹配最低未使用的数字

时间:2013-03-30 10:34:47

标签: sql ms-access access-vba

我在MSAccess中收到了查询结果。

QueryMatch :
InvoiceNumber   RegionNumber  Group
9448180         73657         A
9448180         74170         A
9448180         74171         A
9448180         78761         A
9448196         73657         A
9448196         74170         A
9448196         74171         A
9448196         78761         A
9448201         73657         A
9448201         74170         A
9448201         74171         A
9448201         78761         A

1234567         12345         B
so on..

Table 2:
RegionNumber  InvoiceNumber
73657
74170
74171
78761

查询有一个长列表,由组分隔。 对于x InvoiceNumbers,可以有x + n RegionNumber。 n = 0到25。 一个RegionNumber必须仅与每个组的一个InvoiceNumber匹配。 我们如何更新Table2?

让我们为最小的RegionNumber做匹配,以匹配Matchresult中最小的InvoiceNumber。

将最后一个RegionNumber保留为NULL。

请提供VBA或仅通过查询完成此操作? 为每个RegionNumber选择MIN(InvoiceNumber)将产生相同的InvoiceNumber。

由于

1 个答案:

答案 0 :(得分:1)

让我们考虑以下[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,然后将其中一个“剩余”分配给RegionNumber 678.

现在,要找到给定RegionNumber的最低未使用的 InvoiceNumber,我们需要排除已经写入[Table 2]的任何一个。因此,假设我们已经将InvoiceNumber 123“赋予”RegionNumber 789,那么找到RegionNumber 678的合适候选者的一种方法是...

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中为这些区域“第一次拍摄”,可能通过手动为这些“困难”区域分配更高的优先级。