2009-08-05 17 views
4

私はソートの問題に苦しんでいます。MS ACCESS - 階層ツリーの並べ替え

次のように私は、あるテーブルを持っている:私は、次のダミーデータと非環式ツリーを持っている

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; 

誰かが私を助けてくれますか?

+0

何dooes略語CTEはどういう意味ですか? –

+0

CTE = SQL-99標準の一部であるCommon Table Expression。SQL Server 2005に導入されました。MSDNの「Common Table Expressions」(http://msdn.microsoft.com/en-us/library/ms190766.aspx)を参照してください。 。 – onedaywhen

+0

どのバージョンのAccessを使用していますか? Access 2010には、階層型データを処理するための新しいフィールド型があります。 –

答えて

0

次のコードが役に立つかどうかわかりませんが、ここではBOMアルゴリズムを使用しています。

+0

「Joe Celko」は、ここでOPがネストされたセットモデルではなく隣接リストモデルを使用しているため動作しません...彼らが完全にスキーマを改訂しない限り、劇的ですが考慮する価値があります。 – onedaywhen

0

テストコードのその完全な、しかし、私はVBのコードで動作する何かをしました。その本当に醜いと遅いが、それは動作します。私は今それを掃除して、ちょうどそれを働かせました。解は再帰関数です。この関数は、ノードに子があることがわかった場合にそれ自身を呼び出します。配列を上書きしてしまったように見えました。コードはひどいですが、それはうまくいきます。データベースは小さくて(< 1000レコード)、速度は問題ではありません。コメントと回答をありがとう、誰かが私がより良い解決策を知っているなら、私はそれを聞くのが大好きです。

 
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

パフォーマンスが考慮されていない場合、この非常に単純な解決策は動作します:

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 
関連する問題