2

データベースに格納されているグループ(フォルダー)のフルパスのリストを取得する必要があります。

select * from groups;

group_id    parent_group_id    name
--------    ---------------    -------------------------------
1           NULL               Root
2           1                  Folder1
3           2                  Folder2
4           3                  Folder3

グループの可能な深さに制限はありません(ほぼ無期限にネストされる可能性があります)ので、レベルをいくつ持つことができるかを事前に知りません。

クエリから次の結果を取得し、それをテーブルにロードして、他のクエリでgroup_idsとフルパスを結合するために使用できるようにしたいと思います。

group_id   path
--------   --------------------------------------------
1          /Root
2          /Root/Folder1
3          /Root/Folder1/Folder2
4          /Root/Folder1/Folder2/Folder3

私は同様のニーズを持つ他のいくつかの例を見てきましたが、それが私が望むものに完全に適合することは決してないようであり、明確な例がなければ、私はそれを一人で行うのに苦労しています。

私が考えることができた唯一のことは、同じテーブルのエイリアスを最大レベル数まで結合することでした。これは多くの場合があり、それは実用的ではありません。グループごとに何とか再帰的にループしてツリーを上に移動し、最後になるまで変数にパスを追加してから、最も深い子IDとそのフルパスをテーブルに格納する方法が必要になります。

パフォーマンスも非常に重要です。これは本番データベースであり、速度を落とす余裕はありません。そのため、必要なときにのみダンプして、静的データを再利用したいと考えています。最終的には、それぞれがgroup_idにリンクしている何千ものレコードをダンプし、それらのフルパスを出力したいと思います。

すべてを無料で提供せずに、誰かが私を正しい方向に向けて、コピー元の一般的な例を教えてもらえますか?

SQL Server2008R2を使用しています。

4

2 に答える 2

6

再帰CTEを使用して解決できる可能性があるもののように聞こえます。CTE(または一般的なテーブル式)を使用すると、テーブルやビューを作成しなくても、テーブルのような構造を作成できます。CTEを使用すると、再帰クエリを作成することもできます。これは、この場合に非常に役立ちます。この構造により、CTEをそれ自体に結合し、ここで達成しようとしている「カスケード」タイプの結果を得ることができます。

たとえば、次のようなことができます。

WITH grouppaths (group_id, group_path) AS
(
    SELECT group_id, pathname
    FROM GroupPath
    WHERE parent_group_id IS NULL

    UNION ALL

    SELECT gp.group_id, gps.group_path + '/' + gp.pathname
    FROM GroupPath gp
    JOIN grouppaths gps ON gps.group_id = gp.parent_group_id
)

SELECT 
  group_id, group_path
FROM
  grouppaths

これは、SqlFiddleを使用してここで確認できます。

Microsoftは、CTEの使用に関する情報とサンプルをここで提供しています:http://msdn.microsoft.com/en-us/library/ms190766%28v=sql.105%29.aspx

より具体的には、このリンクは再帰CTEに関する詳細情報を提供します:http://msdn.microsoft.com/en-us/library/ms186243%28v=sql.105%29.aspx

于 2013-03-07T22:31:17.207 に答える
4

Matt Johnsonによって投稿されたリンクに基づいて、私は自分の課題を次のように解決することができました。

WITH group_paths (group_id, group_path)
AS
(
-- Anchor member definition
    SELECT g.group_id, cast('/'+g.name as varchar(max)) as group_path
    FROM dbo.blgroup AS g
    WHERE parent_group_id=0
    UNION ALL
-- Recursive member definition
    SELECT g.group_id, cast(group_path + '/' + g.name as varchar(max))
    FROM dbo.blgroup AS g
    INNER JOIN group_paths AS gp
        ON g.parent_group_id = gp.group_id
)
-- Statement that executes the CTE
SELECT group_id, group_path
FROM group_paths

結果は次のようになります。これはまさに私が必要としていたものです。

group_id    group_path
----------- ----------------------------------------
1000001     /Servers
1000002     /Depot
1000003     /Jobs
1000004     /Component Templates
1000006     /System Packages
1000005     /Components
1000008     /Patch Repository
1000007     /Device
1000010     /Device/Imported
1000011     /Device/Provisioned
1000009     /Patch Repository/Patches By Subscription
2000148     /Components/Customers
于 2013-03-08T00:21:51.097 に答える