我想将磁盘上存在的目录存储到数据库中,同时维护它们的层次结构/树结构。
这是一个无花果,
(ROOT) / \ Dir2 Dir3 / \ \ Dir4 Dir5 Dir6 / Dir7
我正在使用 SQLite 数据库。
请建议我在SQLite数据库中存储上述结构的sql查询。
以及在我选择目录时检索目录的完整路径的查询。
即。假设我选择了Dir6然后我会得到完整的路径,如ROOT / Dir2 / dir3 / dir7
答案 0 :(得分:36)
这是SQLite的快速闭包表示例。我没有包含将项目插入现有树的语句。相反,我刚刚手动创建了语句。您可以在Models for hierarchical data幻灯片中找到插入和删除语句。
为了我在插入目录的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 |
+----+---------+
答案 1 :(得分:1)
您将分层数据表示为一系列节点,每个节点都有一个ID和一个父ID。 您可以将您存储在名为DIRTAB的表中,该表包含2个ID列,另一个表用于单个目录名的文本:
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)
答案 2 :(得分:1)
我认为您应该阅读有关修改预订树遍历的方法:http://www.sitepoint.com/hierarchical-data-database/
该链接讨论了将分层数据存储到关系数据库中的两种方法:邻接列表模型和修改后的预订树遍历算法。