2009-08-05 13 views
4

Je suis confronté à un problème de tri.MS ACCESS - Tri arborescent hiérarchique

J'ai une table qui est la suivante:

aspect_id (int) 
aspect_text (memo) 
root_id (int) which has as a foreign key a aspect_id 

J'ai un arbre non cyclique avec les données fictives suivantes:

aspect_id aspect_text root_id 

1   root   null 
2   aspect1  1 
3   aspect2  1 
4   aspect3  2 
5   aspect5  4 

Dans l'exemple les données sont triées correctement, dans ma base de données ce n'est pas. Je veux trier qu'il commence à l'élément racine, puis trouve un enfant, sortie de cet enfant et le fait de manière récursive.

Avec CTE, c'est assez faisable. L'accès ne supporte pas cela. Avec CTE ce serait quelque chose comme:

WITH aspectTree (aspect_id, root_id, Level#) AS 
(
     Select 
      aspect.aspect_id, 
      aspect.root_id, 
      0 
     FROM aspect 
     WHERE aspect.aspect_id = 44 
    UNION ALL 
     SELECT 
      aspect.aspect_id, 
      aspect.root_id, 
      T.Level# + 1 
     FROM aspect 
     INNER JOIN aspectTree AS T 
      On T.aspect_id = aspect.root_id 
) 
SELECT * FROM aspectTree; 

Quelqu'un peut-il m'aider?

+0

Quels dooes l'acronyme CTE signifie? –

+0

CTE = expression de table commune, partie de la norme SQL-99 et introduite dans SQL Server 2005. Voir MSDN 'Using Common Table Expressions' (http://msdn.microsoft.com/fr-fr/library/ms190766.aspx) . – onedaywhen

+0

Quelle version d'Access utilisez-vous? Access 2010 a un nouveau type de champ pour gérer les données hiérarchiques. –

Répondre

0

Je ne sais pas si ce qui suit fonctionnera pour vous mais ici vous allez utiliser des algorithmes de nomenclature.

+0

Le 'Joe Celko' ne fonctionnera pas parce que l'OP ici utilise le modèle de liste d'adjacence et non le modèle des ensembles imbriqués ... à moins qu'ils ne révisent complètement leur schéma, drastique mais peut être utile;) – onedaywhen

0

Son plein de code de test, mais je l'ai fait quelque chose qui fonctionne dans le code vb. C'est vraiment moche et lent, mais ça marche. Je le nettoie maintenant, je l'ai juste fonctionné. La solution est une fonction récursive. La fonction appelle elle-même si elle trouve que le noeud a des enfants. Il a semblé écraser les tableaux, c'est pourquoi c'est un tableau de tableaux. Le code est hideux, mais ça marche et c'est tout ce dont j'avais besoin. La base de données est et restera petite (< 1000 enregistrements) donc la vitesse n'est pas un problème. Merci pour les commentaires et les réponses, si quelqu'un sait que je ferais mieux de la solution, j'aimerais l'entendre.

 
Private Function Fillarray(value As Integer) 
Dim done As Boolean 

j = j + 1 
esql = "select aspect_id from aspect where root_id = " & value 
Set rec(j) = db.OpenRecordset(esql) 
Dim k As Integer 
k = j 
Do While Not rec(k).EOF 
done = True 
arra(i) = rec(k).Fields(0) 
Dim temp1 As String 
temp1 = DLookup("[aspects]", "[aspect]", "[aspect_id] = " & rec(k).Fields(0)) 
db.Execute "INSERT INTO sortedaspect (aspect_id, aspect) VALUES (" & rec(k).Fields(0) & ", '" & temp1 & "')" 

     esql = "select aspect_id from aspect where root_id = " & rec(k).Fields(0) 

     Set rec(90) = db.OpenRecordset(esql) 
     Do While Not rec(90).EOF And done 
      'fix this without a loop,you only need to know if it has childs... 
      Fillarray (rec(k).Fields(0)) 
      done = False 

     Loop 
     'next child 

rec(k).MoveNext 
'value = arra(i) 
i = i + 1 
'MsgBox arra(i - 1) 
Loop 

End Function 
1

Si les performances ne sont pas une considération, cette solution assez simple fonctionnerait:

Public Function GetLevel(ByVal lngNodeId As Long) As Long 

    Dim varRootId As Variant 

    varRootId = DLookup("root_id", "aspect", "aspect_id=" & lngNodeId) 

    If IsNull(varRootId) Then 
     GetLevel = 0 
    Else 
     GetLevel = GetLevel(varRootId) + 1 
    End If 

End Function 

Vous pouvez ensuite utiliser cette fonction dans votre clause ORDER BY:

SELECT aspect.* 
FROM aspect 
ORDER BY GetLevel([aspect_id]), aspect_text