使用 Access 中的起始零件在物料清单中查找最终项目的方法是什么?阵列?递归函数?

What is an approach to find the end item in a Bill of Materials with starting part in Access? Arrays? Recursive Function?

我正在寻找开始的方法,不一定是完整的解决方案。我的问题是如何构建一个程序,该程序采用零件号并在物料清单中上升到每个级别,检查下一个更高的组件是否列在单独的 table 中,同时仍然牢记第一个零件号用户输入?我已经包含了示例数据以及该程序在我脑海中的工作方式。

我相信我需要使用数组或某种递归函数。我真的不知道除了 SQL 之外找到下一个更高议会的最佳方法是什么。

我有一个带有部件号的 table 和他们的下一个更高的装配体,它给出了称为 tbl_PartandNHA 的各种部件号的材料清单:

Part Number NHA
Part A  Part L
Part A  Part M
Part L  Part S
Part M  Part S
Part M  Part R
Part S  Part Y
Part S  Part Z
Part R  Part Y
Part B  Part N
Part N  Part Q
Part Q  Part W

我还有另一个 table,其中包含满足某些条件的零件号列表。我称之为 tbl_PartMeetsCriteria.

零件符合标准

Part Z
Part Q

W 部分的物料清单如下所示:

Part W
    Part Q
        Part N
            Part B

该程序被赋予了一个零件号,并爬上材料清单寻找 tbl_PartMeetsCriteria 中列出的零件号。该算法将像这样工作:找到 B 部分的 NHA。NHA 是 N 部分。检查 tbl_PartMeetCriteria 中的 N 部分。不是在table所以找NHA。它是 Q 部分。检查 tbl_PartMeetsCriteria 中的 Q 部分。它在 table 中。停止例程并显示消息框“Q 部分在 table 中。 B 部分构建 Q 部分” 实际上,我的程序会将匹配存储在别处。

现在我们要分析A部分。包含 A 部分的材料清单写在这里。

Part Y
    Part S
        Part L
            Part A
        Part M
            Part A  
    Part R
        Part M
            Part A
Part Z
    Part S
        Part L
            Part A
        Part M
            Part A

程序将看到 A 部分有两个 NHA(L 部分、M 部分)。该程序将检查 tbl_PartMeetsCriteria 中的每一项。然后程序必须分支出来。它必须先查找 M 部分的 NHA,然后再查找 R 部分的 NHA。结果会找不到任何匹配项。然后它必须返回并检查 L 部分的 NHA,然后检查 S 部分以在 tbl_PartMeetsCriteria 中查找匹配项。 S 部分的 NHA 是 Y 部分和 Z 部分。程序将找到与 Z 部分的匹配项并说“Z 部分在 table 中。 A 部分构建 Z 部分”

我的问题是如何构建一个程序,可以在材料清单的每个选项上找到匹配项?

我将其视为一系列嵌套数组,如下所示:

A 部分(L 部分(S 部分(Y 部分、Z 部分))、M 部分(R 部分(Y 部分)、S 部分(Y 部分、Z 部分)))

我知道如何使用 SQL 查询某些内容。我了解数组和 FOR 循环的基础知识,但我不知道这是否是正确的方法。问题在于示例数据是物料清单的简化版本。根据较低的部件号,有数千个连接和更多级别。该程序将需要数组中的动态数量的数组来存储选项并调查下一个更高程序集的每个可能线程,直到找到匹配项或到达最高级别。我怎么能这样做?有比数组更好的选择吗?

真正关心的是允许您编辑源数据的方式。圆引用会导致无限递归,这就是为什么任何递归设置都不允许直接输入的原因。任何输入都必须经过验证。

无论如何,这里有一些使用 VBA 的递归示例,后面是您的问题的答案,您可以在其中阅读和扩展以满足您的需要。

下面的代码将递归地搜索下一个元素,直到找不到下一个元素。 F(x) = F(f(x))

Public Function RecursiveSingleNode(PartNumber As String, Optional NHA As String, Optional recursionDepth As Integer) As String
'Will return the last element of a first found node!
'
    On Error Resume Next
    If PartNumber = "" Then Exit Function

    If (Nz(DLookup("nha", "tbl_PartandNHA", "partnumber='" & PartNumber & "'"), "") <> "") Then
        RecursiveSingleNode = RecursiveSingleNode(Nz(DLookup("nha", "tbl_PartandNHA", "partnumber='" & PartNumber & "'"), ""))
    Else
        RecursiveSingleNode = PartNumber
    End If

End Function

此代码与上面相同,但检查是否在您的 meetCriteria 中找到该值 table。

Public Function RecursiveSingleNodeFindMeet(PartNumber As String, Optional NHA As String, Optional recursionDepth As Integer) As String

    On Error Resume Next
    If PartNumber = "" Then Exit Function

    If (Nz(DLookup("partnumber", "PartMeetsCriteria", "partnumber='" & PartNumber & "'"), "") <> "") Then
        RecursiveSingleNodeFindMeet = Nz(DLookup("partnumber", "PartMeetsCriteria", "partnumber='" & PartNumber & "'"), "")
    Else
        RecursiveSingleNodeFindMeet = RecursiveSingleNodeFindMeet(Nz(DLookup("nha", "tbl_PartandNHA", "partnumber='" & PartNumber & "'"), ""))

    End If

End Function

在您的示例 table 中,您有多个以相同元素开头的节点。 像 A, L..; A, M.. 每个节点都必须单独搜索。为此,您需要一个要搜索的所有节点的列表。使用标准 sql 并将其与递归方法结合使用。

理论上,你会列出所有节点

  • 1> A-L, L-S, S-Y,
  • A-m, m-s, s-y,

这对于 M 和 S 的每个子节点都是相同的。因此您需要将此列表函数包含在您的递归函数中。 于是就变成了

  1. 获取下一个元素
  2. 检索下一个元素的所有节点
  3. 递归搜索每个元素并检查是否在匹配条件中找到 table。
  4. 对节点中的每个下一个元素执行此操作,直到节点到达终点

查找以用户输入开头的所有节点:

Public Function FindNHA(PartNumber As String)

    Dim SQL_GET As String
    SQL_GET = "SELECT * FROM tbl_PartandNHA WHERE(partnumber like '" & PartNumber & "')"

    Dim MyRs As Recordset
    Set MyRs = CurrentDb.OpenRecordset(SQL_GET)
    If Not (MyRs.BOF Or MyRs.EOF) Then

        Dim Result As String

        While Not MyRs.EOF
            'Recursive method to find the part matching in partmeetcriteria table
            Result = FindNHAR(Nz(MyRs("partnumber"), ""), Nz(MyRs("nha"), ""))
            If (Result <> "") Then
                FindNHA = Result
                Exit Function
            End If

            MyRs.MoveNext
        Wend
    End If
End Function



Public Function FindNHAR(PartNumber As String, Optional NHA As String, Optional recursionDepth As Integer) As String
    'Recursively search for next element and check if it's found in your PartMeetsCriteria. Return blank if not

    On Error Resume Next
    If PartNumber = "" Then Exit Function

    If (Nz(DLookup("partnumber", "PartMeetsCriteria", "partnumber='" & PartNumber & "'"), "") <> "") Then
        ' if partnumber is found in meetsCriteria table return it
        FindNHAR = Nz(DLookup("partnumber", "PartMeetsCriteria", "partnumber='" & PartNumber & "'"), "")
    ElseIf (Nz(DLookup("partnumber", "PartMeetsCriteria", "partnumber='" & NHA & "'"), "") <> "") Then
            ' if NHAis found in meetsCriteria table return it
        FindNHAR = Nz(DLookup("partnumber", "PartMeetsCriteria", "partnumber='" & NHA & "'"), "")
    Else
        If Not NHA = "" Then
            'For each element, check if it has multiple nodes and search each element in each node again, starting with NHA
            FindNHAR = FindNHA(NHA)
        Else
'Same as above since NHA is empty, use partnumber
            FindNHAR = FindNHAR(Nz(DLookup("nha", "tbl_PartandNHA ", "partnumber='" & PartNumber & "'"), ""))
        End If

    End If

End Function

用法:立即尝试这个 window

?FindNHA("Part S") Part Z
?FindNHA("Part A") Part Z
?FindNHA("Part B") Part Q
?FindNHA("Part R") ""
?FindNHA("Part M") Part Z
?FindNHA("Part N") Part Q

您应该知道这只是概念验证。您可以使用它来了解 VBA 的递归功能,但您必须在实施之前采取额外的安全措施。您可以使用子函数缩短几行代码。我留下更大的版本供您理解。 RecursionDepth 是给你实现的。