Repetition of query to produce report

非 Y 不嫁゛ 提交于 2019-12-08 04:13:09

问题


I am creating a bill of materials program.

There are two main tables named Products and Sub_Products.

In the Products table, the fields are (Product_Name, Code). In the Sub_Products table, the fields are (Code, Sub_Name).

The tables are linked with code, i.e.: one product is made up of many sub_products, each sub_product is a product as well, making it have many sub_products.

I have created a query that reads a product and gets its sub_products. I need a query to compare Sub_Name with Product_Name and then check more sub_products, continuing until no more sub_products are found.

Any ideas?


回答1:


I guess you will have to use a script rather than SQL query to loop through them. Assuming that the products can be nested more than 3 levels.




回答2:


I've been working on this exact problem in an ASP.NET MVC application. A function that gathered all the subproducts for each product and recursed on each subproduct worked well. We have some BOMs that are 15 levels deep.




回答3:


I realize this question was asked a long time ago, but I had a very similar question and finally figured out a good answer. So I am posting it here in case anyone needs to know how to create a Bill of Materials.

In my example there is a table called "Part_Item_Table" which lists parent items and all of their childeren. Those childeren can also be parents to other childeren. The difficulty was that the BOM could be 3 levels deep all the way up to 30 levels deep or more. My "Part_Item_Table" also lists whether items are "Make" items or not. Only "Make" items will have childeren. The table you are querying may not have that feature, but the code below will probably still be helpful to get the idea.

This set of code uses several things that were new to me such as recursive code, calling a query I had already created and passing in a variable using the querydef methods, and using recordsets to get large information sets in and out of functions. I also used a sequence field in my BOM Table so I could sort by it and view the BOM in the order it is meant to be (Showing visually which level 3 items roll up into which level 2 items). If there is something that can be improved I am open to suggestions. This does work for my needs right now and hopefully it is helpful to someone else.

Option Compare Database

Public stFirstPart As String
Private Const BOMTable As String = "BOM_Table"  'Set this variable to the name of the table
Private Const ComponentQ As String = "GetComponentsQ"   'Set to the name of the query in the database

Function BOM()
Dim stQuery As String   'Used to make a query
Dim i As Integer        'Used to create the sequence number
Dim iLevel As Integer   'Used to show BOM level
Dim rsParent, rsBOMTable As DAO.Recordset     'Used to hold query results

'Make sure there is a part number in the form
If IsNull(Forms![Entry Form]![Part_Number]) Then
    Debug.Print "There is no part number entered in the form"
    MsgBox "There is no part number in the form.", vbOKOnly, "Can't fool me."
    Exit Function
End If

stFirstPart = Forms![Entry Form]![Part_Number]  'Get the top part number from the form

'Make sure this is a Make item.  Only make items will have childeren
stQuery = "SELECT ITEM.ITEM_NO, ITEM.MAKE_BUY_FLAG, ITEM.CURRENT_FLAG " & _
        " FROM PART_ITEM_TABLE AS ITEM " & _
        " WHERE (((ITEM.ITEM_NO)='" & stFirstPart & "') AND ((ITEM.MAKE_BUY_FLAG)='M') AND ((ITEM.CURRENT_FLAG)='Y'));"

Set rsParent = CurrentDb.OpenRecordset(stQuery)

If rsParent.EOF And rsParent.BOF Then
    Debug.Print "This is not a make item"
    MsgBox "This is not a Make item.", vbOKOnly, "I tried."
    Exit Function
End If

'Clear the BOM table and load this first part number
DoCmd.SetWarnings False

DoCmd.RunSQL "Delete from " & BOMTable & ""
Set rsBOMTable = CurrentDb.OpenRecordset(BOMTable, dbOpenDynaset)

i = 1
iLevel = 1

rsParent.MoveFirst
With rsBOMTable
    .AddNew
    !Sequence = i
    !Level = iLevel
    !Item_Number = stFirstPart
    !Make_Buy = "M"
    .Update
End With

rsParent.Close
Set rsParent = Nothing
rsBOMTable.Close
Set rsBOMTable = Nothing

   '-----------------------------------------------------------------------------------------------------------------------------------
   'Start going down levels
   '-----------------------------------------------------------------------------------------------------------------------------------
iLevel = 2
Call RecursiveLevels(stFirstPart, iLevel, i)

DoCmd.SetWarnings True
End Function

Function RecursiveLevels(PartNumber As String, iLevel As Integer, i As Integer)
Dim rsLevels As DAO.Recordset
Dim stPart As String

Set rsLevels = GetComponents(PartNumber)

If rsLevels.BOF And rsLevels.EOF Then
    Debug.Print "This was a Make item with no children.  That shouldn't happen. "; PartNumber
    GoTo ExitPoint
End If

rsLevels.MoveFirst
Do While Not rsLevels.EOF
    If rsLevels!Make_Buy <> "M" Then   ' Anything that is not a Make item is written to the BOM table one line at a time.
        i = i + 1
        Call WriteToBOMTable(iLevel, i, rsLevels!Parent_Number, rsLevels!Component_Number, rsLevels!Make_Buy)

    Else    'The Make item is written to the table, then we query for all of its children
        stPart = rsLevels!Component_Number
        i = i + 1

        Call WriteToBOMTable(iLevel, i, rsLevels!Parent_Number, rsLevels!Component_Number, rsLevels!Make_Buy)

        If stPart = stFirstPart Then    'Check to make sure this recursive thing doesn't go on forever.
            Debug.Print "This part number is the same as the first part number.  Circ Reference. "; stPart
            GoTo ExitPoint
        End If

        iLevel = iLevel + 1     ' get ready to go one level deeper
        Call RecursiveLevels(stPart, iLevel, i)

    End If
rsLevels.MoveNext
Loop

ExitPoint:
iLevel = iLevel - 1     'Done with this level.  Come back up a level.
rsLevels.Close
Set rsLevels = Nothing
End Function

Function WriteToBOMTable(Level As Integer, i As Integer, ParentNumber As String, ComponentNumber As String, MakeBuy As String)
Dim rsBOMTable As DAO.Recordset

Set rsBOMTable = CurrentDb.OpenRecordset(BOMTable, dbOpenDynaset)

With rsBOMTable
.AddNew
!Parent_Number = ParentNumber
!Item_Number = ComponentNumber
!Level = Level
!Make_Buy = MakeBuy
!Sequence = i
.Update
End With

Debug.Print "Level: "; Level; "Component: "; ComponentNumber

rsBOMTable.Close
Set rsBOMTable = Nothing

End Function

Function GetComponents(PartNumber As String) As DAO.Recordset
Dim qdf As QueryDef

Set qdf = CurrentDb.QueryDefs(ComponentQ)
qdf.Parameters("PartNumber") = PartNumber
Set GetComponents = qdf.OpenRecordset

End Function


来源:https://stackoverflow.com/questions/1393626/repetition-of-query-to-produce-report

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!