ディレクトリ(ディスク上に存在する)をデータベースに保存し、階層/ツリー構造を維持したいと思います。
これが図です:
(ROOT) /\ Dir2 Dir3 /\\ Dir4 Dir5 Dir6 / Dir7
SQLiteデータベースを使用しています。
私に提案してください:
上記の構造をSQLiteデータベースに保存するSQLクエリ、および
ディレクトリを選択したときにディレクトリのフルパスを取得するためのクエリ。
つまり、Dir7
を選択すると、ROOT/Dir2/Dir4/Dir7
のようなフルパスを取得する必要があります。
SQLiteの簡単なクロージャテーブルの例を次に示します。既存のツリーにアイテムを挿入するためのステートメントは含めていません。代わりに、ステートメントを手動で作成しました。挿入ステートメントと削除ステートメントは、 階層データのモデル スライドにあります。
ディレクトリのIDを挿入するときの正気のために、IDと一致するようにディレクトリの名前を変更しました。
(ROOT)
/ \
Dir2 Dir3
/ \ \
Dir4 Dir5 Dir6
/
Dir7
テーブルを作成する
CREATE TABLE `filesystem` (
`id` INTEGER,
`dirname` TEXT,
PRIMARY KEY (`id`)
);
CREATE TABLE `tree_path` (
`ancestor` INTEGER,
`descendant` INTEGER,
PRIMARY KEY (`ancestor`, `descendant`)
);
ディレクトリをfilesystem
テーブルに挿入します
INSERT INTO filesystem (id, dirname) VALUES (1, 'ROOT');
INSERT INTO filesystem (id, dirname) VALUES (2, 'Dir2');
INSERT INTO filesystem (id, dirname) VALUES (3, 'Dir3');
INSERT INTO filesystem (id, dirname) VALUES (4, 'Dir4');
INSERT INTO filesystem (id, dirname) VALUES (5, 'Dir5');
INSERT INTO filesystem (id, dirname) VALUES (6, 'Dir6');
INSERT INTO filesystem (id, dirname) VALUES (7, 'Dir7');
クロージャテーブルパスを作成します
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 1);
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 2);
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 3);
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 4);
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 5);
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 6);
INSERT INTO tree_path (ancestor, descendant) VALUES (1, 7);
INSERT INTO tree_path (ancestor, descendant) VALUES (2, 2);
INSERT INTO tree_path (ancestor, descendant) VALUES (2, 4);
INSERT INTO tree_path (ancestor, descendant) VALUES (2, 5);
INSERT INTO tree_path (ancestor, descendant) VALUES (2, 7);
INSERT INTO tree_path (ancestor, descendant) VALUES (3, 3);
INSERT INTO tree_path (ancestor, descendant) VALUES (3, 6);
INSERT INTO tree_path (ancestor, descendant) VALUES (4, 4);
INSERT INTO tree_path (ancestor, descendant) VALUES (4, 7);
INSERT INTO tree_path (ancestor, descendant) VALUES (5, 5);
INSERT INTO tree_path (ancestor, descendant) VALUES (6, 6);
INSERT INTO tree_path (ancestor, descendant) VALUES (7, 7);
いくつかのクエリを実行します
# (ROOT) and subdirectories
SELECT f.id, f.dirname FROM filesystem f
JOIN tree_path t
ON t.descendant = f.id
WHERE t.ancestor = 1;
+----+---------+
| id | dirname |
+----+---------+
| 1 | ROOT |
| 2 | Dir2 |
| 3 | Dir3 |
| 4 | Dir4 |
| 5 | Dir5 |
| 6 | Dir6 |
| 7 | Dir7 |
+----+---------+
# Dir3 and subdirectories
SELECT f.id, f.dirname
FROM filesystem f
JOIN tree_path t
ON t.descendant = f.id
WHERE t.ancestor = 3;
+----+---------+
| id | dirname |
+----+---------+
| 3 | Dir3 |
| 6 | Dir6 |
+----+---------+
# Dir5 and parent directories
SELECT f.id, f.dirname
FROM filesystem f
JOIN tree_path t
ON t.ancestor = f.id
WHERE t.descendant = 5;
+----+---------+
| id | dirname |
+----+---------+
| 1 | ROOT |
| 2 | Dir2 |
| 5 | Dir5 |
+----+---------+
# Dir7 and parent directories
SELECT f.id, f.dirname
FROM filesystem f
JOIN tree_path t
ON t.ancestor = f.id
WHERE t.descendant = 7;
+----+---------+
| id | dirname |
+----+---------+
| 1 | ROOT |
| 2 | Dir2 |
| 4 | Dir4 |
| 7 | Dir7 |
+----+---------+
SELECT f.id, f.dirname
FROM filesystem f
JOIN tree_path t
ON t.ancestor = f.id
WHERE t.descendant = (
SELECT id
FROM filesystem
WHERE dirname LIKE '%7%'
);
+----+---------+
| id | dirname |
+----+---------+
| 1 | ROOT |
| 2 | Dir2 |
| 4 | Dir4 |
| 7 | Dir7 |
+----+---------+
計算されたメソッドについて読む必要があると思います変更されたプレオーダーツリートラバーサル: http://www.sitepoint.com/hierarchical-data-データベース/
このリンクでは、階層データをリレーショナルデータベースに格納するための2つの方法、隣接リストモデルと変更されたプレオーダーツリー走査アルゴリズムについて説明しています。
変更されたプレオーダーツリートラバーサルメソッドの主なアイデアは、ナビゲーションとサブツリーの選択を補助するためのポインターですべてのノードに注釈を付けることです。
階層データは、それぞれがIDと親IDを持つ一連のノードとして表します。 2つのID列と1つの個々のディレクトリ名のテキスト用のDIRTABというテーブルにを格納できます。
ID -- as a primary key
PARENT_ID -- refers to the ID of the parent row in DIRTAB
DIRNAME -- the text of the name eg Dir5
SQLiteには、Oracleが階層データを処理する必要があるというCONNECT BY句がありませんが、醜いSQLを受け入れる準備ができている場合は、階層的なものを概算できると思います。
SELECT (CASE WHEN p5.DIRNAME IS NOT NULL THEN p5.DIRNAME || '/' ELSE '' END) ||
(CASE WHEN p4.DIRNAME IS NOT NULL THEN p4.DIRNAME || '/' ELSE '' END) ||
(CASE WHEN p3.DIRNAME IS NOT NULL THEN p3.DIRNAME || '/' ELSE '' END) ||
(CASE WHEN p2.DIRNAME IS NOT NULL THEN p2.DIRNAME || '/' ELSE '' END) ||
(CASE WHEN p1.DIRNAME IS NOT NULL THEN p1.DIRNAME || '/' ELSE '' END) ||
p0.DIRNAME as FULLPATH
FROM DIRTAB p0
LEFT OUTER JOIN DIRTAB p1 ON p1.ID = p0.PARENT_ID
LEFT OUTER JOIN DIRTAB p2 ON p2.ID = p1.PARENT_ID
LEFT OUTER JOIN DIRTAB p3 ON p3.ID = p2.PARENT_ID
LEFT OUTER JOIN DIRTAB p4 ON p4.ID = p3.PARENT_ID
LEFT OUTER JOIN DIRTAB p5 ON p5.ID = p4.PARENT_ID
WHERE p0.DIRNAME = 'Dir6'
ここでの問題は、ディレクトリ構造の最大の深さを予測し、それに対処するためにSQLステートメントを拡張する必要があることです。例として6つのレベルを実行しました。
また、SQLiteは空の文字列を連結するのに問題がないと思います。 (一部のDBは、それらをnullとして扱い、式の結果全体をnullに変換します)