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。 グループごとに、1 つの RegionNumber と 1 つの 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 値のリストと、それぞれが持つ個別の 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 でこれらの地域に「最初のショット」を与える必要がある場合があります。おそらく、これらの「難しい」地域により高い優先度を手動で割り当てることによって可能です。

于 2013-03-30T12:56:51.273 に答える