2013年7月31日水曜日

「共通テーブル式を使用する再帰クエリ」で楽々階層データを取得

MS SQL Serverにおいて、親IDを持つようなテーブルで再帰的に階層データを取得したいことがありました。
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だけでこんなに簡単に階層データが取得できるとは・・・今までなんで気が付かなかったんでしょうか。。
これからはバリバリ使いたいと思います。

0 件のコメント:

コメントを投稿