2009-08-05 4 views
4

Ich kämpfe mit einem Sortierproblem.MS ACCESS - Hierarchische Baumsortierung

Ich habe eine Tabelle, die wie folgt ist:

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

I eine nicht zyklische Struktur mit den folgenden Dummy-Daten habe:

aspect_id aspect_text root_id 

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

Im Beispiel der Daten sortieren richtig, in meiner Datenbank nicht. Ich möchte sortieren, dass es am Wurzelelement beginnt, dann ein Kind findet, dieses Kind ausgibt und das rekursiv tut.

Mit CTE ist es ziemlich machbar. Access unterstützt dies nicht. Mit CTE wäre es so etwas wie:

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; 

Kann mir jemand helfen?

+0

Was dooes das Akronym CTE bedeutet? –

+0

CTE = allgemeiner Tabellenausdruck, Teil des SQL-99-Standards und eingeführt in SQL Server 2005. Siehe MSDN 'Verwenden allgemeiner Tabellenausdrücke' (http://msdn.microsoft.com/en-us/library/ms190766.aspx) . – onedaywhen

+0

Welche Version von Access verwenden Sie? Access 2010 verfügt über einen neuen Feldtyp zum Behandeln von hierarchischen Daten. –

Antwort

0

Ich weiß nicht, ob das Folgende für Sie funktioniert, aber hier gehen Sie mit Bill of Materials Algorithmen.

+0

Die 'Joe Celko' wird nicht funktionieren, weil das OP hier das Adjazenzlistenmodell verwendet, nicht das verschachtelte Mengenmodell ... es sei denn, sie überarbeiten ihr Schema drastisch, aber es lohnt sich, darüber nachzudenken;) – onedaywhen

0

Sein voller Testcode, aber ich habe etwas, das in vb Code funktioniert. Es ist wirklich hässlich und langsam, aber es funktioniert. Ich säubere es jetzt, habe es gerade funktioniert. Die Lösung ist eine rekursive Funktion. Die Funktion ruft sich selbst auf, wenn sie feststellt, dass der Knoten childs hat. Es scheint die Arrays zu überschreiben, deshalb ist es ein Array von Arrays. Der Code ist hässlich, aber es funktioniert und das ist alles was ich brauche. Die Datenbank ist und bleibt klein (< 1000 Datensätze), so Geschwindigkeit ist kein Problem. Danke für die Kommentare und Antworten, wenn jemand eine bessere Lösung kennt, würde ich es gerne hören.

 
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

Wenn die Leistung nicht eine Überlegung ist, diese recht einfache Lösung funktionieren würde:

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 

Sie könnten dann diese Funktion in Ihrem ORDER BY-Klausel verwenden:

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