-1

I’m looking for an approach to start, not necessarily a full solution. My question is how do I construct a program that takes a part number and goes up each level in a Bill of Materials, checks if the Next Higher Assembly is listed in a separate table while still keeping in mind the first part number that the user inputs? I have included example data and how the program would work in my mind.

I believe I would need to use arrays or some kind of recursive function of some sort. I don’t really know what would be the best approach besides the SQL to find the Next Higher Assembly.

I have a table with part numbers and their Next Higher Assembly like this that gives the Bill of Materials for various part numbers called 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

I also have another table with a list of part numbers that meet some criteria. I’ll call this tbl_PartMeetsCriteria.

Part Meets Criteria

Part Z
Part Q

For Part W, the bill of materials look like this:

Part W
    Part Q
        Part N
            Part B

The program is given a part number and climbs up the bill of materials looking for a part number that is listed in tbl_PartMeetsCriteria. The algorithm would work like this: Find NHA of Part B. The NHA is Part N. Check Part N in tbl_PartMeetCriteria. It is not in the table so find NHA. It is Part Q. Check Part Q in tbl_PartMeetsCriteria. It is in the table. Stop routine and show a msgbox “Part Q is in the table. Part B builds Part Q” In reality, my program will store the match elsewhere.

Now we have Part A to analyze. The Bill of Materials with Part A is written here.

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

The program will see that Part A has two NHAs (Part L, Part M). The program will check each of these in tbl_PartMeetsCriteria. Then the program must branch out. It has to look for the NHA of Part M and then the NHA of Part R. It will turn up with no matches. Then it has to go back and check the NHA of Part L then Part S to look for matches within tbl_PartMeetsCriteria. The NHAs of Part S is Part Y and Part Z. The program will find a match with Part Z and say “Part Z is in the table. Part A builds Part Z”

My question is how do I construct a program that can go up each option of the bill of materials to find a match?

I see it as a series of nested arrays like this:

Part A (Part L (Part S (Part Y, Part Z)), Part M (Part R (Part Y), Part S (Part Y, Part Z)))

I understand how to query something using SQL. I understand the basics of arrays and FOR loops, but I don't know if that is the right approach. The problem is that the example data is a simplified version of the Bill of Materials. There are thousands of connections and a lot more levels depending on the lower part number. The program would need a dynamic amount of arrays within arrays to store the options and investigate each possible thread of next higher assemblies until it finds a match or gets to the highest level. How could I do this? Is there a better option than arrays?

  • Access (JET/Ace) SQL doesn't do recursion or loops. As for a VBA solution, this question is too broad. There are a lot of ways to go about it, and alternatives to arrays, such as objects and collections. – Erik A Feb 12 '18 at 17:38
  • Can you give a few pointers about objects and collections? Like some resources or links. That would be helpful. – accessuser Feb 12 '18 at 18:10
  • Have a look at Joe Celko's example at [Queries: BOM, with Joe Celko Nested Sets](http://access.mvps.org/access/queries/qry0023.htm) – Rene Feb 12 '18 at 18:18
  • Objects are a core concept of programming in object-oriented programming languages. [This](https://youtu.be/2vBD_R7dsic) is a very basic youtube tutorial that covers some of the basics. However, for further understanding, I could recommend an entire course on object-oriented programming, and parents and children in OOP. For collections, see [MSDN](https://msdn.microsoft.com/en-us/vba/language-reference-vba/articles/collection-object) – Erik A Feb 12 '18 at 18:28
  • See here for basic recursion in VBA with recordsets: https://stackoverflow.com/a/2701099/3820271 – Andre Feb 12 '18 at 18:46
  • @Andre Thank you Andre and Rene for these answers. Those are the breadcrumbs I was looking for to start this program. – accessuser Feb 12 '18 at 19:04
  • You say "Find NHA of Part x" but all of your examples are reversed? you can't climb up from unknown depth of the tree. You should calculate A->B will be much easier to understand the concept. – Krish Feb 13 '18 at 10:39
  • @krishKM My apologies, when I referred to Part A, I meant Part A is the user input. The program would find the NHA of Part A using recordsets. The Bill of Materials for Part Y and Part Z show that the NHA of Part A is Part L and Part M. Climbing up from unknown depth of the tree is the problem I'm wrestling with, because I won't know what part the user will give and I won't know which part number above it will be in tbl_PartMeetsCriteria. – accessuser Feb 13 '18 at 14:20
  • your tbl_PartandNHA table has an ID or any of your table uses ID? – Krish Feb 13 '18 at 15:33
  • @krishKM The actual table just has Part ID and NHA ID instead of Part Numbers, but there is not an ID for any given pair of Part Number and NHA. They are composite keys. – accessuser Feb 13 '18 at 18:07

1 Answers1

0

The real concern is the way you are allowed to edit your source data. Circle reference would cause an infinite recursion and that's why any recursion setup never allow direct input. Any input has to be validated.

Anyhow here is some recursion samples using VBA followed by the answer of your question where you can read and expand to suit your needs.

Below code will recursively search for the next element until no next element is found. 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

This code is same as above but checks whether the value is found in your 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

In your example table, you have multiple nodes starting with same element. like A, L..; A, M.. each node has to be searched separately. For that you need a list of all nodes to search. Use standard sql and couple it with recursive method.

In theory, you will list all nodes

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

this is same for each sub nodes for M and S. Hence you need this listing function to be included in your recursive function. So it becomes

  1. Get the next element
  2. Retrieve all nodes for the next element
  3. search each element recursively and check if found in matching criteria table.
  4. Do this for each next element in a node until node reached end

to find all nodes starting with user input:

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

Usage: try this in your immediate 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

You should be aware this is just a proof of concept. You can use this to understand VBA's recursion capabilities but you must take additional security measurements before implementing this. You may shorten few lines of codes using sub functions. I leave the bigger version for you to understand. RecursionDepth is for you to implement.

Krish
  • 5,917
  • 2
  • 14
  • 35