Question

J'ai une table de job

Id
ParentID
jobName
jobStatus

Le ParentID racine est 0.

Est-il possible dans Access pour créer une requête pour trouver une racine pour un job donné? La base de données est mdb sans tables liées. La version d'accès est 2003. Un job peut avoir plusieurs niveaux de profondeur petits enfants.

Était-ce utile?

La solution

Non, ce n'est pas. Les requêtes récursives sont pris en charge dans SQL Server après sServer 2005, mais pas dans Access.

Si vous savez d'avance le nombre de niveaux, vous pouvez écrire une requête, mais ce ne serait pas une récursive.

Dans SQL Server, CTE (extension SQL) est utilisé pour cela: voir http://blog.crowe.co.nz/archive/2007/09/06/Microsoft-SQL-Server-2005 --- CTE-exemple-de-a-simple.aspx

SQL régulier cependant ne prend pas en charge la récursivité.

Autres conseils

Il est possible dans Access pour créer une requête pour trouver la racine de votre travail donné. Ne pas oublier la puissance des fonctions VBA. Vous pouvez créer une fonction récursive dans un module VBA et utiliser le résultat comme un champ de sortie dans votre requête.

Exemple:

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

Vous pouvez appeler cette fonction récursive de votre requête en utilisant le générateur de requêtes ou en tapant simplement le nom de la fonction avec des arguments dans un champ de requête.

Il donnera la racine.

(je reconnais l'OP est d'un an maintenant, mais je suis obligé de répondre quand tout le monde dit ce qui est impossible est possible).

Vous ne pouvez pas interroger récursive.

Vous pouvez faire un certain nombre arbitraire de jointures gauche, mais vous ne pourrez monter autant de niveaux que vous avez rejoint.

Vous pouvez aussi utiliser "Nested Set modèle" de Celko pour récupérer tous les parents. Cela nécessitera la modification de la structure de votre table, d'une façon qui rend plus compliqué insertions et mises à jour.

Cela ne peut pas être fait en utilisant SQL pur dans Access, mais un peu VBA va un long chemin.

Ajoutez une référence à Microsoft Scripting Runtime . ( Outils -> Références ... )

Cela suppose que l'identifiant est unique, et qu'il n'y a pas de cycles: par exemple, Le parent A est B, mais le parent B est 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 voici donc la vraie affaire. Tout d'abord, quel est le public cible pour votre requête .. un formulaire? rapport? Fonction / proc?

Formulaire: mises à jour de besoin? utiliser le contrôle TreeView alors que maladroit cela fonctionnera bien. Rapport: en cas ouvert, utilisez une forme de paramètre pour définir le niveau « Boss Job », puis gérer la récursivité et remplir vba un jeu d'enregistrements avec les données dans l'ordre souhaité . établir des rapports à ce recordset et rempli d'enregistrements traiter le rapport.  Fonction / procédure: fonctionne à peu près le même que la charge de données décrites dans le rapport ci-dessus. Grâce à un code, gérer le nécessaire « arbre qui marche » et stocker le jeu de résultats dans l'ordre souhaité dans un processus et recordset au besoin.

La contribution de Zev m'a donné beaucoup d'inspiration et d'apprentissage. Cependant, nécessaire pour faire des modifications au code. S'il vous plaît noter que ma table est appelée "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

Et il y a une autre fonction utile dans le même contexte. « ChildHasParent » retourne vrai, si correspond à l'enfant le ParentID fourni à tous les niveaux d'imbrication.

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top