美文网首页
树形结构与关系数据库之闭包表

树形结构与关系数据库之闭包表

作者: 魔能野猪 | 来源:发表于2018-02-20 00:13 被阅读0次

    在《SQL反模式》中介绍了多种把树存到关系数据库中的方法,下面介绍一下其中闭包表的用法。

    建表与插入数据(SQLite3)

    
    CREATE TABLE NODE(
    id  INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL
    );
    CREATE  TABLE TREE_PATH(
    anc INTEGER NOT NULL, --祖先节点
    des INTEGER NOT NULL, --子孙节点
    pc  INTEGER NOT NULL, --是否为父子节点 1/0
    PRIMARY KEY (anc,des)
    );
    --示例树
    -- root(0)
    --     |
    --     A(1)
    --     |___A1(2)
    --     |___A2(3)
    --     B(4)
    --     |___B1(5)
    --     |___B2(6)
    --     |___C(7)
    --         |___C1(8)
    --         |___D(9)
    --             |___E(10)
    
    
    INSERT INTO NODE(id,name) VALUES (0,'ROOT');
    INSERT INTO NODE(id,name) VALUES (1,'A');
    INSERT INTO NODE(id,name) VALUES (2,'A1');
    INSERT INTO NODE(id,name) VALUES (3,'A2');
    INSERT INTO NODE(id,name) VALUES (4,'B');
    INSERT INTO NODE(id,name) VALUES (5,'B1');
    INSERT INTO NODE(id,name) VALUES (6,'B2');
    INSERT INTO NODE(id,name) VALUES (7,'C');
    INSERT INTO NODE(id,name) VALUES (8,'C1');
    INSERT INTO NODE(id,name) VALUES (9,'D');
    INSERT INTO NODE(id,name) VALUES (10,'E');
    
    UPDATE sqlite_sequence SET seq=10 WHERE name='NODE';
    
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,1,1);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,2,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,3,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,4,1);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,5,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,6,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,7,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,8,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,9,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (0,10,0);
    
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (1,1,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (2,2,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (3,3,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (4,4,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (5,5,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (6,6,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (7,7,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (8,8,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (9,9,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (10,10,0);
    
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (1,2,1);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (1,3,1);
    
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (4,5,1);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (4,6,1);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (4,7,1);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (4,8,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (4,9,0);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (4,10,0);
    
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (7,8,1);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (7,9,1);
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (7,10,0);
    
    INSERT INTO TREE_PATH(anc,des,pc) VALUES (9,10,1);
    

    删除子树

    假设要删除子树#7

    DELETE
    FROM TREE_PATH
    WHERE TREE_PATH.des IN (SELECT t.des FROM TREE_PATH t WHERE t.anc=7)
    

    移动子树

    假设我们要把子树#7从节点#4移动到节点#1

    1.分离子树,删除子树节点与其祖先的关系

    DELETE FROM
    TREE_PATH
    WHERE
        des IN (SELECT d.des FROM TREE_PATH d WHERE d.anc=7)
        AND
        anc IN (SELECT a.anc FROM TREE_PATH a WHERE a.des=7 AND a.anc!=a.des)
    

    2.将上一步分离出的子树用笛卡尔积嫁接到#1下

    INSERT INTO TREE_PATH(anc,des,pc)
    SELECT
        super.anc,
        sub.des,
        CASE
            WHEN
                super.anc=1 AND sub.des=7 THEN 1
            ELSE 0
        END pc
    FROM
        TREE_PATH super
        CROSS JOIN
        TREE_PATH sub
    WHERE
        super.des=1 AND sub.anc=7
    

    相关文章

      网友评论

          本文标题:树形结构与关系数据库之闭包表

          本文链接:https://www.haomeiwen.com/subject/ttmwtftx.html