1

我在 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。

谢谢

4

1 回答 1

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 值的列表以及每个具有的不同 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.

于 2013-03-30T12:56:51.273 回答