VB.NETから使用するのですが、VB.NET側で実装するとパフォーマンスも悪そうだし、あまり綺麗じゃないのでどうにかならないかと思っていたところ、SQL Serverでズバリそのようなデータを取得できるSQLがかけることがわかりました。
今までの案件でもそういうのが使いたいことがあったのですが、、気づきませんでした。。不覚です。
MSDNの以下のページが参考になりました。
というか、そのものです。
共通テーブル式を使用する再帰クエリ
http://msdn.microsoft.com/ja-jp/library/ms186243(v=sql.100).aspx
MSDNは結構硬いのではじめなんだか面倒なことを書いてそうな気がする・・・とか思ったのですが、よくよく読んでみると簡単に実装できることがわかりました。
こんな感じで実装してみました。WITH MyRes([no], [name], [parent_no], [Level], [Path]) AS ( SELECT [t_dat].[no], [t_dat].[name], [t_dat].[parent_no] , 0 AS [Level] ,cast([t_dat].[no] as nvarchar(4000)) as [Path] FROM [t_dat] WHERE [t_dat].[no] = 1 UNION ALL SELECT [D].[no], [D].[name], [D].[parent_no], [Level] + 1 ,[Path] + '-' + cast([D].[no] as nvarchar(4000)) FROM [t_dat] AS [D] INNER JOIN [MyRes] AS [M] ON [M].[no] = [D].[parent_no] ) SELECT * FROM [MyRes] ORDER BY [Path];
Levelは階層の番号で、一番上が0になります。
Pathは階層を順番に上からハイフン区切りで表します。
例えば、1-5-6-10のようになります。
これでソートすると階層でつながっているもの順でならんでくれます。
parent_noの設定を間違うと無限ループになったりすることもあるかもしれませんが、デフォルトでは100階層までの取得のようです。
これはMAXRECURSIONの値を設定すれば変更できるようです。
簡単なSQLだけでこんなに簡単に階層データが取得できるとは・・・今までなんで気が付かなかったんでしょうか。。
これからはバリバリ使いたいと思います。