Is it possible to create a recursive query in Access?

前端 未结 7 1958
有刺的猬
有刺的猬 2020-11-27 19:12

I have a job table

Id
ParentID
jobName
jobStatus

The root ParentID is 0.

Is it possible in Access to create a query to

相关标签:
7条回答
  • 2020-11-27 19:33

    This cannot be done using pure SQL in Access, but a little VBA goes a long way.

    Add a reference to the Microsoft Scripting Runtime (Tools -> References...).

    This assumes that the ID is unique, and that there are no cycles: e.g. A's parent is B, but B's parent is A.

    Dim dict As Scripting.Dictionary
    
    Function JobRoot(ID As Long) As Long
        If dict Is Nothing Then
            Set dict = New Scripting.Dictionary
            Dim rs As DAO.Recordset
            Set rs = CurrentDb.OpenRecordset("SELECT ID, ParentID FROM Job", dbOpenForwardOnly, dbReadOnly)
            Do Until rs.EOF
                dict(rs!ID) = rs!ParentID
                rs.MoveNext
            Loop
            Set rs = Nothing
    
            Dim key As Variant
            For Each key In dict.Keys
                Dim possibleRoot As Integer
                possibleRoot = dict(key)
                Do While dict(possibleRoot) <> 0
                    possibleRoot = dict(possibleRoot)
                Loop
                dict(key) = possibleRoot
            Next
        End If
        JobRoot = dict(ID)
    End Function
    
    Sub Reset() 'This needs to be called to refresh the data
        Set dict = Nothing
    End Sub
    
    0 讨论(0)
  • 2020-11-27 19:40

    OK so here's the REAL deal. First, what is the target audience for your query.. a form? report? function/proc?

    Form: Need updates? use the treeview control while clumsy it will work nicely. Report: in the open event use a parameter form to set the "Boss Job" level then handle the recursion in vba and fill a recordset with the data in the order desired. set the reports recordset to this filled recordset and process the report. Function/Procedure: works pretty much the same as a the data load described in the report above. Through code, handle the necessary "tree walking" and store the result set in the desired order in a recordset and process as needed.

    0 讨论(0)
  • 2020-11-27 19:45

    No, It isn't. Recursive queries are supported in SQL Server after SServer 2005, but not in Access.

    If you know the number of levels beforehand, you could write a query, but it wouldn't be a recursive one.

    In SQL Server, CTE (An SQL extension) is used for that : see http://blog.crowe.co.nz/archive/2007/09/06/Microsoft-SQL-Server-2005---CTE-Example-of-a-simple.aspx

    Regular SQL however does not have Recursivity support.

    0 讨论(0)
  • 2020-11-27 19:49

    I had a related problem working with a treeview structure, when a user wants to delete a node, he wants to delete all then nodes under that tree. Childs, childs of childs etc etc.

    A job for recursion....

    So to delete the data in your table to match the treeview node deletes, use a recursive function that will delete the node, and recurse down and delete all the nodes that are children, grandchildren ect.

    example of the function:

    Public Sub RemoveChildKeys(MyKey)
    ' deletes passed key and removes all children and grandchildren ect etc of passed key recursively
    
       Dim TheDB As DAO.Database
       Dim TheTable As DAO.Recordset
       Dim MySql As String
    
       Set TheDB = CurrentDb
    
       MySql = "Select * from TblIndex WHERE [Parent]=" & MyKey & ";"
       Set TheTable = TheDB.OpenRecordset(MySql)
    
       While Not TheTable.EOF
         RemoveChildKeys (TheTable!Key)  ' <---- Calls itself
         TheTable.MoveNext
       Wend
    
       DoCmd.RunSQL "Delete * FROM TblIndex WHERE [Key]=" & MyKey  ' delete in table
    
    End Sub
    
    0 讨论(0)
  • 2020-11-27 19:53

    You can't recursively query.

    You can either do some arbitrary number of left joins, but you'll only be able to go up as many levels as you have joins.

    Or you can use Celko's "Nested Set Model" to retrieve all parents. This will require modifying your table structure, in way that makes inserts and updates more complicated.

    0 讨论(0)
  • 2020-11-27 19:54

    Zev's contribution gave me a great deal of inspiration and learning. However, needed to do some edits to the code. Please note that my table is called "tblTree".

    Dim dict As Scripting.Dictionary
    
    Function TreeRoot(ID As Long) As Long
        If dict Is Nothing Then
            Set dict = New Scripting.Dictionary ' Requires Microsoft Scripting Runtime
            Dim rs As DAO.Recordset
            Set rs = CurrentDb.OpenRecordset("tblTree", dbOpenForwardOnly, dbReadOnly)
            Do Until rs.EOF
                dict.Add (rs!ID), (rs!ParentID)
                rs.MoveNext
            Loop
            Set rs = Nothing
        End If
    
        TreeRoot = ID
    
        Do While dict(TreeRoot) <> 0    ' Note: short version for dict.item(TreeRoot)
            TreeRoot = dict(TreeRoot)
        Loop
    End Function
    

    And there is another useful function in the same context. "ChildHasParent" returns true, if the child's matches the supplied ParentID in any level of nesting.

    Function ChildHasParent(ID As Long, ParentID As Long) As Boolean
        If dict Is Nothing Then
            Set dict = New Scripting.Dictionary ' Requires Microsoft Scripting Runtime
            Dim rs As DAO.Recordset
            Set rs = CurrentDb.OpenRecordset("tblTree", dbOpenForwardOnly, dbReadOnly)
            Do Until rs.EOF
                dict.Add (rs!ID), (rs!ParentID)
                rs.MoveNext
            Loop
            Set rs = Nothing
        End If
    
        ChildHasParent = False
    
        Do While dict(ID) <> 0    ' Note: short version for dict.item(TreeRoot)
            ID = dict(ID)
            If ID = ParentID Then
                ChildHasParent = True
                Exit Do
            End If
        Loop
    End Function
    
    0 讨论(0)
提交回复
热议问题