5

並び替えで悩んでいます。

次のようなテーブルがあります。

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;
4

3 に答える 3

1

パフォーマンスが考慮されない場合、次のかなり単純なソリューションが機能します。

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
于 2010-12-20T19:24:05.387 に答える
0

以下がうまくいくかどうかはわかりませんが、ここでは Bill of Materials アルゴリズムを使用します。

于 2009-08-05T19:38:31.043 に答える
0

その完全なテスト コードですが、私は vb コードで動作する何かをしました。それは本当に醜くて遅いですが、うまくいきます。私は今それを片付けて、ちょうどそれを働かせました。解決策は再帰関数です。ノードに子があることが判明した場合、この関数はそれ自体を呼び出します。配列を上書きしているように見えたので、配列の配列です。コードは恐ろしいですが、機能し、必要なのはそれだけです。データベースは小さく (1000 レコード未満) 維持されるため、速度は問題になりません。コメントと回答をありがとう、誰かが私がより良い解決策を知っているなら、私はそれを聞きたい.

プライベート関数 Fillarray (整数としての値)
Dim done As Boolean

j = j + 1
esql = "ルート ID = " & 値のアスペクトからアスペクト ID を選択
rec(j) = db.OpenRecordset(esql) を設定します。
Dim k As Integer
k = j
do While Not rec(k).EOF
完了 = 真
arra(i) = rec(k).Fields(0)
Dim temp1 を文字列として
temp1 = DLookup("[アスペクト]", "[アスペクト]", "[アスペクト ID] = " & rec(k).Fields(0))
db.Execute "INSERT INTO sortedaspect (aspect_id、aspect) VALUES (" & rec(k).Fields(0) & ", '" & temp1 & "')"

        esql = "ルート ID = " & rec(k).Fields(0) のアスペクトからアスペクト ID を選択

        rec(90) = db.OpenRecordset(esql) を設定します。
        Do While Not rec(90).EOF And done
            'ループなしでこれを修正します。子があるかどうかだけを知る必要があります...
            Fillarray (rec(k).Fields(0))
            完了 = 偽

        ループ
      「次の子

rec(k).MoveNext
' 値 = arra(i)
私 = 私 + 1
'MsgBox arra(i - 1)
ループ

終了機能
于 2009-08-07T11:39:18.333 に答える