MS ACCESS - Иерархический вид дерева - PullRequest
4 голосов
/ 05 августа 2009

Я борюсь с проблемой сортировки.

У меня есть таблица, которая выглядит следующим образом:

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

У меня есть нециклическое дерево со следующими фиктивными данными:

aspect_id  aspect_text  root_id 

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

В примере данные отсортированы правильно, в моей базе данных их нет. Я хочу отсортировать, что он начинается с корневого элемента, затем находит потомка, выводит этого потомка и делает это рекурсивно

С CTE это вполне выполнимо. Доступ не поддерживает это. С CTE это было бы что-то вроде:

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;

Кто-нибудь может мне помочь?

Ответы [ 3 ]

1 голос
/ 20 декабря 2010

Если производительность не учитывается, это довольно простое решение будет работать:

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

Затем вы можете использовать эту функцию в предложении ORDER BY:

SELECT aspect.*
FROM aspect
ORDER BY GetLevel([aspect_id]), aspect_text
0 голосов
/ 07 августа 2009

Это полный тестовый код, но я сделал то, что работает в коде VB. Это действительно уродливо и медленно, но это работает. Я сейчас убираю это, только что заработало. Решение является рекурсивной функцией. Функция вызывает себя, если обнаруживает, что у узла есть дочерние элементы. Казалось, переписать массивы, поэтому его массив массивов. Код ужасен, но он работает, и это все, что мне нужно. База данных есть и останется небольшой (<1000 записей), поэтому скорость не является проблемой. Спасибо за комментарии и ответы, если кто-то знает, что я нашел лучшее решение, я хотел бы услышать его. <br />

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
0 голосов
/ 05 августа 2009

Я не знаю, сработает ли для вас следующее, но здесь вы используете алгоритмы спецификации материалов.

...