Ist es möglich, eine rekursive Abfrage in Access zu erstellen?
Frage
Ich habe eine job
Tabelle
Id
ParentID
jobName
jobStatus
Die Wurzel ParentID ist 0.
Ist es möglich, in Access eine Abfrage zu erstellen, eine Wurzel für einen bestimmten job
zu finden?
Die Datenbank wird ohne verknüpften Tabellen MDB. Die Access-Version ist 2003. Ein job
können mehrere Ebenen große Kinder tief sein.
Lösung
Nein, ist es nicht. Rekursive Abfragen werden in SQL Server nach sServer 2005 unterstützt, aber nicht in Access.
Wenn Sie die Anzahl der Ebenen im Voraus wissen, können Sie eine Abfrage schreiben, aber es wäre eine rekursive man nicht sein.
In SQL Server, CTE (Eine SQL-Erweiterung) ist dafür verwendet: siehe http://blog.crowe.co.nz/archive/2007/09/06/Microsoft-SQL-Server-2005 --- CTE-Beispiel-of-a-simple.aspx
Regelmäßige SQL jedoch nicht über Rekursivität Unterstützung.
Andere Tipps
Es ist möglich, in Access eine Abfrage zu erstellen, die Wurzel Ihres bestimmten Jobs zu finden. Vergessen Sie nicht die Macht der VBA-Funktionen. Sie können eine rekursive Funktion in einem VBA-Modul erstellen und das Ergebnis als Ausgabefeld in der Abfrage verwenden.
Beispiel:
Public Function JobRoot(Id As Long, ParentId As Long) As Long
If ParentId = 0 Then
JobRoot = Id
Exit Function
End If
Dim Rst As New ADODB.Recordset
Dim sql As String
sql = "SELECT Id, ParentID FROM JobTable WHERE Id = " & ParentId & ";"
Rst.Open sql, CurrentProject.Connection, adOpenKeyset, adLockReadOnly
If Rst.Fields("ParentID") = 0 Then
JobRoot = Rst.Fields("Id")
Else
JobRoot = JobRoot(Id, Rst.Fields("ParentID")) ' Recursive.
End If
Rst.Close
Set Rst = Nothing
End Function
Sie können diese rekursive Funktion aus der Abfrage aufrufen, indem Sie den Query Builder verwendet oder nur mit Argumenten in einem Abfragefeld im Funktionsnamen eingeben.
Es wird die Wurzel erhalten.
(Ich erkenne das OP ein Jahr alt jetzt ist, aber ich bin gezwungen, um zu antworten, wenn jeder sagt, was ist unmöglich möglich ist).
Sie können nicht rekursiv abgefragt werden.
Sie können entweder tun einige beliebige Anzahl von links schließt sich, aber Sie werden nur in der Lage sein, so viele Ebenen zu gehen, wie Sie haben beitritt.
Oder Sie benutzen Celko der "Nested Sets" um alle Eltern zurückzuholen. Dies erfordert Ihre Tabellenstruktur ändern, in Art und Weise, die Einfügungen und Aktualisierungen komplizierter macht.
Das kann nicht mit reinem SQL in Access getan werden, aber ein wenig VBA geht einem langen Weg.
Fügen Sie einen Verweis auf die Microsoft Scripting Runtime . ( Extras -> Referenzen ... )
Dies setzt voraus, dass die ID eindeutig ist, und dass es keine Zyklen: z.B. Eine der Eltern ist B, aber B der Eltern ist 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
OK also hier ist die eigentliche Behandlung. Erstens, was ist die Zielgruppe für Ihre Anfrage .. ein Formular? Bericht? Funktion / proc?
Form: Need-Updates? Verwenden Sie die treeview Steuerung während ungeschickt es schön funktioniert. Bericht: im offenen Ereignisse einen Parameter Formular verwenden, um die „Boss Job“ Pegel setzen dann die Rekursion in vba handhaben und einen Re-Cord mit den Daten in der gewünschten Reihenfolge füllen. stellen Sie die Berichte Cord-Set zu diesem gefüllt Cord-Set und verarbeiten den Bericht. Funktion / Prozedur: funktioniert so ziemlich das gleiche wie eine die Datenlast im Bericht beschrieben. Durch Code, behandelt den notwendigen „Baum walking“ und speichern Sie das Ergebnis gesetzt in der gewünschten Reihenfolge in einem Re-Cord und Prozess nach Bedarf.
Zev Beitrag hat mir viel Inspiration und Lernen. Allerdings benötigt, um einige Änderungen an dem Code zu tun. Bitte beachten Sie, dass mein Tisch „tblTree“ genannt wird.
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
Und es ist eine weitere nützliche Funktion im selben Kontext. „ChildHasParent“ gibt true zurück, wenn das Kind das mitgelieferte ParentID in jeder Ebene der Verschachtelung entspricht.
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