2017-08-16 8 views
3

私はファイルシステムを表すいくつかのテーブルで作業しており、各フォルダのフルパスをフラット化された文字列として選択する必要があります。SQL - パスにNULL以外の隣接リストを変換する

最初の表は、各フォルダの詳細を示しています:

CREATE TABLE Folders(
    FolderID int IDENTITY(1,1) NOT NULL, 
    [Name] nvarchar(255) NOT NULL) 

第2のテーブルリストはフォルダ関係のクロージャを推移:サンプルデータについては

CREATE TABLE FolderClosures(
    FolderClosuresID int IDENTITY(1,1) NOT NULL, 
    AncestorFolderID int NOT NULL, --Foreign key to Folders.FolderID 
    DescendantFolderID int NOT NULL --Foreign key to Folders.FolderID 
    IsDirect bit NOT NULL) 

、のは、以下のフォルダが存在すると仮定しましょう:

Documents/ 
Documents/Finance/ 
Documents/HumanResources/ 
Documents/HumanResources/Training/ 

これらは、次のようにこれらのテーブルに保持されます:

| FolderID | Name   | 
+----------+----------------+ 
|  1 | Documents  | 
|  2 | Finance  | 
|  3 | HumanResources | 
|  4 | Training  | 

| FolderClosureID | AncestorFolderID | DescendantFolderID | IsDirect | 
+-----------------+------------------+--------------------+----------+ 
|    1 |    1 |     1 |  0 | 
|    2 |    2 |     2 |  0 | 
|    3 |    1 |     2 |  1 | 
|    4 |    3 |     3 |  0 | 
|    5 |    1 |     3 |  1 | 
|    6 |    4 |     4 |  0 | 
|    7 |    1 |     4 |  0 | 
|    8 |    3 |     4 |  1 | 

注意すべきいくつかの詳細:

  1. すべてのフォルダがFolderClosuresAncestorFolderID = DescendantFolderID AND IsDirect = 0で "アイデンティティ行" を持っています。最上位のフォルダではない

  2. すべてのフォルダはIsDirect = 1

  3. FolderClosuresAncestorFolderID <> DescendantFolderID AND IsDirect = 0フォルダごとに多くの行を含むことができるFolderClosuresに正確に一つの行を有します。これらはそれぞれ、「祖父母」以上の遠い関係を表しています。

  4. 列にはNULLを指定できないため、指定されたフォルダが最上位のフォルダであることが明示的に示されていません。これは、FolderClosuresに行がないことを確認することによってのみ識別できます。IsDirect = 1 AND DescendantFolderID = SomeIDここで、SomeIDは問題のフォルダのIDです。

私はこのデータを返すクエリを実行できるようにしたい:

| FolderID | Path        | 
+----------+------------------------------------+ 
|  1 | Documents/       | 
|  2 | Documents/Finance/     | 
|  3 | Documents/HumanResources/   | 
|  4 | Documents/HumanResources/Training/ | 

フォルダは、無制限の深さでネストされたが、現実的におそらく唯一の10のレベルまですることができます。クエリでは、数千のフォルダのパスを返す必要があります。

データが隣接リストとして保持されている場合、このタイプのクエリの作成に関する多くのアドバイスがありますが、このような推移的クロージャ設定の回答は見つかりませんでした。私が見つけた隣接リストのソリューションは、null可能な親フォルダIDで永続化されている行に頼っていますが、ここでは機能しません。

希望の出力を得るにはどうすればよいですか?

それが助け場合は、所望の出力を得るために、私はSQL Serverを使用しています2016年

答えて

2

一つの方法は、再帰クエリを行うことです。そのためには、IsDirect = 1の行だけを使用し、直接親を持たないすべてのフォルダとしてアンカーをFolderClosuresに使用することをお勧めします。これはすべてのルートフォルダにする必要があります。

WITH FoldersCTE AS (
    SELECT F.FolderID, CAST(F.Name as NVARCHAR(max)) Path 
    FROM Folders F 
    WHERE NOT EXISTS (
     SELECT 1 FROM FolderClosures FC WHERE FC.IsDirect = 1 AND FC.DescendantFolderID = F.FolderID 
    ) 
    UNION ALL 
    SELECT F.FolderID, CONCAT(PF.Path, '\', F.Name) 
    FROM FoldersCTE PF 
      INNER JOIN FolderClosures FC 
       ON FC.AncestorFolderID = PF.FolderId 
       AND FC.IsDirect = 1 
      INNER JOIN Folders F 
       ON F.FolderID = FC.DescendantFolderID 
) 
SELECT * 
FROM FoldersCTE 
OPTION (MAXRECURSION 1000) --> how many nested levels you think you will have 

これが生成します。

FolderID Path 
1   Documents 
2   Documents\Finance 
3   Documents\HumanResources 
4   Documents\HumanResources\Training 

はそれがお役に立てば幸いです。

関連する問題