重复查询以生成报告

时间:2009-09-08 12:07:49

标签: ms-access ms-access-2007

我正在创建一个物料清单程序。

有两个主要表格ProductsSub_Products

Products表格中,字段为(Product_NameCode)。 在Sub_Products表格中,字段为(CodeSub_Name)。

这些表与代码相关联,即:一个product由多个sub_product组成,每个sub_product也是product,这使得它有很多sub_product秒。

我创建了一个查询product并获取其sub_product的查询。我需要一个查询来将Sub_NameProduct_Name进行比较,然后检查更多sub_product s, 继续,直到找不到sub_product为止。

有什么想法吗?

3 个答案:

答案 0 :(得分:1)

我猜你必须使用脚本而不是SQL查询来循环它们。假设产品可以嵌套超过3个级别。

答案 1 :(得分:0)

我一直在研究ASP.NET MVC应用程序中的这个问题。收集每个产品的所有子产品并在每个子产品上递归的功能运行良好。我们有一些15级深度的物料清单。

答案 2 :(得分:0)

我很久以前就意识到这个问题,但我有一个非常相似的问题,最后找到了一个很好的答案。所以我在这里发帖,以防任何人需要知道如何创建物料清单。

在我的示例中,有一个名为“Part_Item_Table”的表,其中列出了父项和所有孩子。那些孩子也可以成为其他孩子的父母。难点在于BOM可以是3级深度,直到30级或更深。我的“Part_Item_Table”还列出了项目是否为“Make”项目。只有“Make”项目才会有孩子。您查询的表可能没有该功能,但下面的代码可能仍然有助于理解。

这组代码使用了一些对我来说很新的东西,例如递归代码,调用我已经创建的查询以及使用querydef方法传递变量,以及使用记录集来获取和传出函数的大型信息集。我还在物料清单表中使用了一个序列字段,因此我可以按它排序并按照预期的顺序查看物料清单(直观地显示哪个等级3项汇总到哪个等级2项)。如果有什么可以改进的话,我愿意接受建议。这确实适合我现在的需求,希望它对其他人有帮助。

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