Sql 文件系统中目录路径的分层/树数据库

Sql 文件系统中目录路径的分层/树数据库,sql,sqlite,path,tree,hierarchical-data,Sql,Sqlite,Path,Tree,Hierarchical Data,我想将目录(存在于磁盘上)存储到数据库中,保持它们的层次/树结构 这是一个数字: (ROOT) / \ Dir2 Dir3 / \ \ Dir4 Dir5 Dir6 / Dir7 (根

我想将目录(存在于磁盘上)存储到数据库中,保持它们的层次/树结构

这是一个数字:

(ROOT) / \ Dir2 Dir3 / \ \ Dir4 Dir5 Dir6 / Dir7 (根) / \ Dir2 Dir3 / \ \ Dir4 Dir5 Dir6 / 迪尔7 我正在使用SQLite数据库

请建议我:

  • 在SQLite数据库中存储上述结构的SQL查询,以及

  • 当我选择一个目录时检索该目录的完整路径的查询

    i、 e.假设我选择
    Dir7
    ,那么我应该得到完整的路径,如
    ROOT/Dir2/Dir4/Dir7


  • 将层次结构数据表示为一系列节点,每个节点都有一个ID和一个父ID。 您可以将文件存储在一个名为DIRTAB的表中,该表有两个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缺少CONNECT BY子句,即Oracle必须处理分层数据,但我认为,如果您准备接受一些难看的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连接空字符串没有问题。(一些数据库将它们视为null,并将整个表达式结果转换为null)

    下面是一个SQLite的快速闭包表示例。我还没有包括将项插入现有树的语句。相反,我只是手动创建了这些语句。您可以在幻灯片中找到insert和delete语句

    为了在插入目录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`)
    );
    
    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    |
    +----+---------+
    
    将目录插入
    文件系统

    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');
    
    创建闭包表路径

    CREATE TABLE `filesystem` (
      `id` INTEGER,
      `dirname` TEXT,
      PRIMARY KEY (`id`)
    );
    
    CREATE TABLE `tree_path` (
      `ancestor` INTEGER,
      `descendant` INTEGER,
      PRIMARY KEY (`ancestor`, `descendant`)
    );
    
    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    |
    +----+---------+
    
    运行一些查询

    CREATE TABLE `filesystem` (
      `id` INTEGER,
      `dirname` TEXT,
      PRIMARY KEY (`id`)
    );
    
    CREATE TABLE `tree_path` (
      `ancestor` INTEGER,
      `descendant` INTEGER,
      PRIMARY KEY (`ancestor`, `descendant`)
    );
    
    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    |
    +----+---------+
    

    我认为您应该阅读有关caled修改的前序树遍历的方法:

    该链接讨论了将层次数据存储到关系数据库中的两种方法:邻接列表模型和改进的前序树遍历算法

    改进的前序树遍历方法的主要思想是用指针注释所有节点,以辅助导航和子树选择:

    闭包表可能是一个不错的选择。请看一看,也可以看到SQLite mainling列表中再次出现了关于该主题的幻灯片,Eduardo Morras(re)指出了SQLite vtable扩展,用于处理SQLite repo本身的层次结构:1)2)@JOHN:对不起,但我从未使用orientDB,约翰:我不知道你是什么意思,你能举个例子吗?我先读了这些查询,一直在想,“这是怎么回事?”我意识到你的
    树路径
    表是目录图传递闭包的邻接列表表示,回答了问题,“这条路径是另一条路径的可到达后代吗?”和“这条路径是另一条路径的可到达祖先吗?”?“很好。@seh:是的,这是一种非常好的技术。虽然它比简单的邻接列表需要更多的条目,但选择数据的查询要简单得多。但是我不能接受这个荣誉。如果你想了解更多,请查看我在问题下方评论中发布的比尔·卡温链接。请注意,您还可以添加路径长度,这使得查找直接祖先/后代更简单。
    树路径
    表不应该包含“嵌套级别”或“深度”字段以使其成为闭包表吗?