在ETL过程中对递归树的历史维护实验

来源:互联网 发布:淘宝韩国正品女装 编辑:程序博客网 时间:2024/06/05 05:14
  1. -- 当前递归树  
  2. CREATE TABLE TREE_CUR  
  3. (  
  4.   C_CHILD   VARCHAR2(32 BYTE),  
  5.   C_NAME    VARCHAR2(100 BYTE),  
  6.   C_PARENT  VARCHAR2(32 BYTE)  
  7. );  
  8.   
  9. CREATE INDEX IDX1 ON TREE_CUR (C_PARENT);  
  10. CREATE UNIQUE INDEX TREE_CUR_PK ON TREE_CUR (C_CHILD);  
  11.   
  12. ALTER TABLE TREE_CUR ADD (CONSTRAINT TREE_CUR_PK PRIMARY KEY (C_CHILD));  
  13. ALTER TABLE TREE_CUR ADD (CONSTRAINT TREE_CUR_R01 FOREIGN KEY (C_PARENT) REFERENCES TREE_CUR (C_CHILD));  
  14.   
  15. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('A''节点A'NULL);  
  16. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('B''节点B''A');  
  17. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('C''节点C''A');  
  18. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('D''节点D''A');  
  19. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('E''节点E''B');  
  20. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('F''节点F''B');  
  21. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('G''节点G''C');  
  22. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('H''节点H''C');  
  23. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('I''节点I''C');  
  24. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('J''节点J''D');  
  25. Insert into TREE_CUR (C_CHILD, C_NAME, C_PARENT) Values ('K''节点K''D');  
  26. COMMIT;  
  27.   
  28.   
  29. -- 递归历史树  
  30. CREATE TABLE TREE_HIS  
  31. (  
  32.   ID        NUMBER,  
  33.   C_CHILD   VARCHAR2(32 BYTE),  
  34.   C_NAME    VARCHAR2(100 BYTE),  
  35.   P_ID      NUMBER,  
  36.   EFF_DATE  DATE,  
  37.   EXP_DATE  DATE  
  38. );  
  39.   
  40. CREATE INDEX IDX2 ON TREE_HIS (P_ID);  
  41. CREATE UNIQUE INDEX IDX3 ON TREE_HIS (C_CHILD, EXP_DATE);  
  42. CREATE UNIQUE INDEX TREE_HIS_PK ON TREE_HIS (ID);  
  43.   
  44. ALTER TABLE TREE_HIS ADD (CONSTRAINT TREE_HIS_PK PRIMARY KEY (ID));  
  45. ALTER TABLE TREE_HIS ADD (CONSTRAINT TREE_HIS_R01 FOREIGN KEY (P_ID) REFERENCES TREE_HIS (ID));  
  46.   
  47.   
  48. -- 建立更新递归历史树数据的存储过程  
  49. CREATE OR REPLACE PROCEDURE p_tree_his_upd  
  50. IS  
  51.    l_id         tree_his.id%TYPE;  
  52.    l_c_name     tree_his.c_name%TYPE;  
  53.    l_p_id       tree_his.p_id%TYPE;  
  54.    l_exp_date   tree_his.exp_date%TYPE;  
  55.    l_max_date   DATE := TO_DATE ('9999-12-31''yyyy-mm-dd');  
  56.    l_sysdate    DATE := SYSDATE;  
  57. BEGIN  
  58.    -- 对当前树中已删除的节点,则历史树当前版本中以此节点为根的子树都过期  
  59.    FOR i  
  60.       IN (  SELECT id  
  61.               FROM tree_his  
  62.              WHERE     exp_date = l_max_date  
  63.                    AND c_child NOT IN (SELECT c_child FROM tree_cur)  
  64.           ORDER BY id)  
  65.    LOOP  
  66.       SELECT exp_date  
  67.         INTO l_exp_date  
  68.         FROM tree_his  
  69.        WHERE id = i.id;  
  70.   
  71.       IF l_exp_date = l_max_date  
  72.       THEN                                                           -- 避免重复更新  
  73.          UPDATE tree_his  
  74.             SET exp_date = l_sysdate  
  75.           WHERE id IN (    SELECT id  
  76.                              FROM tree_his  
  77.                             WHERE exp_date = l_max_date  
  78.                        START WITH id = i.id  
  79.                        CONNECT BY PRIOR id = p_id);  
  80.       END IF;  
  81.    END LOOP;  
  82.   
  83.    -- 遍历当前树  
  84.    FOR x IN (    SELECT c_child, c_name, c_parent  
  85.                    FROM tree_cur  
  86.              START WITH c_parent IS NULL  
  87.              CONNECT BY PRIOR c_child = c_parent)  
  88.    LOOP  
  89.       -- 根据c_child查找历史树的当前版本  
  90.       BEGIN  
  91.          SELECT id, c_name, p_id  
  92.            INTO l_id, l_c_name, l_p_id  
  93.            FROM tree_his  
  94.           WHERE exp_date = l_max_date AND c_child = x.c_child;  
  95.   
  96.          IF l_c_name != x.c_name  
  97.          THEN                          -- 属性(这里属性只有名字)改变,则历史树当前版本中以此节点为根的子树都过期  
  98.             FOR y IN (    SELECT id,  
  99.                                  c_child,  
  100.                                  c_name,  
  101.                                  p_id  
  102.                             FROM tree_his  
  103.                            WHERE exp_date = l_max_date  
  104.                       START WITH id = l_id  
  105.                       CONNECT BY PRIOR id = p_id)  
  106.             LOOP  
  107.                IF y.id = l_id  
  108.                THEN                                             -- 子树的根,p_id不变  
  109.                   l_p_id := y.p_id;  
  110.                ELSE  
  111.                   SELECT id  
  112.                     INTO l_p_id  
  113.                     FROM tree_his  
  114.                    WHERE     exp_date = l_max_date  
  115.                          AND c_child = (SELECT c_child  
  116.                                           FROM tree_his  
  117.                                          WHERE id = y.p_id);  
  118.                END IF;  
  119.   
  120.                BEGIN  
  121.                   SELECT c_name  
  122.                     INTO l_c_name  
  123.                     FROM tree_cur  
  124.                    WHERE c_child = y.c_child;  
  125.                EXCEPTION  
  126.                   WHEN NO_DATA_FOUND  
  127.                   THEN  
  128.                      l_c_name := y.c_name;  
  129.                END;  
  130.   
  131.                UPDATE tree_his  
  132.                   SET exp_date = l_sysdate  
  133.                 WHERE id = y.id;  
  134.   
  135.                INSERT INTO TREE_HIS (ID,  
  136.                                      C_CHILD,  
  137.                                      C_NAME,  
  138.                                      P_ID,  
  139.                                      EFF_DATE,  
  140.                                      EXP_DATE)  
  141.                     VALUES (seq_tree_his.NEXTVAL,  
  142.                             y.c_child,  
  143.                             l_c_name,  
  144.                             l_p_id,  
  145.                             l_sysdate,  
  146.                             l_max_date);  
  147.             END LOOP;  
  148.          END IF;  
  149.       EXCEPTION  
  150.          WHEN NO_DATA_FOUND  
  151.          THEN                                 -- 新增节点,增加整颗子树,新增子树中的节点在原历史树中都过期  
  152.             FOR y IN (    SELECT c_child, c_name, c_parent  
  153.                             FROM tree_cur  
  154.                       START WITH c_child = x.c_child  
  155.                       CONNECT BY PRIOR c_child = c_parent)  
  156.             LOOP  
  157.                IF y.c_child = x.c_child  
  158.                THEN  
  159.                   BEGIN                                                -- 子树的根  
  160.                      SELECT id  
  161.                        INTO l_p_id  
  162.                        FROM tree_his  
  163.                       WHERE exp_date = l_max_date AND c_child = y.c_parent;  
  164.                   EXCEPTION  
  165.                      WHEN NO_DATA_FOUND  
  166.                      THEN                                        --新增根节点,重构整棵树  
  167.                         l_p_id := NULL;  
  168.                   END;  
  169.                ELSE  
  170.                   SELECT id  
  171.                     INTO l_p_id  
  172.                     FROM tree_his  
  173.                    WHERE     exp_date = l_max_date  
  174.                          AND c_child = (SELECT c_parent  
  175.                                           FROM tree_cur  
  176.                                          WHERE c_child = y.c_child);  
  177.                END IF;  
  178.   
  179.                UPDATE tree_his  
  180.                   SET exp_date = l_sysdate  
  181.                 WHERE exp_date = l_max_date AND c_child = y.c_child;  
  182.   
  183.                INSERT INTO TREE_HIS (ID,  
  184.                                      C_CHILD,  
  185.                                      C_NAME,  
  186.                                      P_ID,  
  187.                                      EFF_DATE,  
  188.                                      EXP_DATE)  
  189.                     VALUES (seq_tree_his.NEXTVAL,  
  190.                             y.c_child,  
  191.                             y.c_name,  
  192.                             l_p_id,  
  193.                             l_sysdate,  
  194.                             l_max_date);  
  195.             END LOOP;  
  196.       END;  
  197.    END LOOP;  
  198.   
  199.    COMMIT;  
  200. END;  
  201. /  
  202.   
  203.   
  204. -- 测试  
  205. /*** 加载初始树,执行三次过程,查看结果 ***/  
  206. EXEC p_tree_his_upd;  
  207. EXEC p_tree_his_upd;  
  208. EXEC p_tree_his_upd;  
  209.   
  210. SELECT * FROM tree_his;  
  211.   
  212.     SELECT *  
  213.       FROM tree_his  
  214.      WHERE exp_date = TO_DATE ('9999-12-31''yyyy-mm-dd')  
  215. START WITH p_id IS NULL  
  216. CONNECT BY PRIOR id = p_id;  
  217.   
  218.   
  219. /*** 修改当前递归树的名称列,执行三次过程,查看结果(修改名称) ***/  
  220. UPDATE tree_cur SET c_name = '节点A1' WHERE c_child = 'A';  
  221. UPDATE tree_cur SET c_name = '节点B1' WHERE c_child = 'B';  
  222. UPDATE tree_cur SET c_name = '节点C1' WHERE c_child = 'C';  
  223. UPDATE tree_cur SET c_name = '节点D1' WHERE c_child = 'D';  
  224. UPDATE tree_cur SET c_name = '节点E1' WHERE c_child = 'E';  
  225. UPDATE tree_cur SET c_name = '节点F1' WHERE c_child = 'F';  
  226. UPDATE tree_cur SET c_name = '节点G1' WHERE c_child = 'G';  
  227. UPDATE tree_cur SET c_name = '节点H1' WHERE c_child = 'H';  
  228. UPDATE tree_cur SET c_name = '节点I1' WHERE c_child = 'I';  
  229. UPDATE tree_cur SET c_name = '节点J1' WHERE c_child = 'J';  
  230. UPDATE tree_cur SET c_name = '节点K1' WHERE c_child = 'K';  
  231. COMMIT;  
  232.   
  233. EXEC p_tree_his_upd;  
  234. EXEC p_tree_his_upd;  
  235. EXEC p_tree_his_upd;  
  236.   
  237. SELECT * FROM tree_his;  
  238.   
  239.     SELECT *  
  240.       FROM tree_his  
  241.      WHERE exp_date = TO_DATE ('9999-12-31''yyyy-mm-dd')  
  242. START WITH p_id IS NULL  
  243. CONNECT BY PRIOR id = p_id;  
  244.   
  245. /*** 修改名称 ***/  
  246. UPDATE tree_cur SET c_name = '节点A2' WHERE c_child = 'A';  
  247. UPDATE tree_cur SET c_name = '节点C2' WHERE c_child = 'C';  
  248. UPDATE tree_cur SET c_name = '节点E2' WHERE c_child = 'E';  
  249. UPDATE tree_cur SET c_name = '节点H2' WHERE c_child = 'H';  
  250. UPDATE tree_cur SET c_name = '节点K2' WHERE c_child = 'K';  
  251. COMMIT;  
  252.   
  253. EXEC p_tree_his_upd;  
  254. EXEC p_tree_his_upd;  
  255. EXEC p_tree_his_upd;  
  256.   
  257. SELECT * FROM tree_his;  
  258.   
  259.     SELECT *  
  260.       FROM tree_his  
  261.      WHERE exp_date = TO_DATE ('9999-12-31''yyyy-mm-dd')  
  262. START WITH p_id IS NULL  
  263. CONNECT BY PRIOR id = p_id;  
  264.   
  265. /*** 修改名称 ***/  
  266. UPDATE tree_cur SET c_name = '节点B2' WHERE c_child = 'B';  
  267. UPDATE tree_cur SET c_name = '节点C3' WHERE c_child = 'C';  
  268. COMMIT;  
  269.   
  270. EXEC p_tree_his_upd;  
  271. EXEC p_tree_his_upd;  
  272. EXEC p_tree_his_upd;  
  273.   
  274. SELECT * FROM tree_his;  
  275.   
  276.     SELECT *  
  277.       FROM tree_his  
  278.      WHERE exp_date = TO_DATE ('9999-12-31''yyyy-mm-dd')  
  279. START WITH p_id IS NULL  
  280. CONNECT BY PRIOR id = p_id;  
  281.   
  282. /*** 增加新的根节点,并改变原来的父子关系 ***/  
  283. INSERT INTO tree_cur VALUES ('X''节点X'NULL);  
  284. INSERT INTO tree_cur VALUES ('Y''节点Y''X');  
  285. UPDATE tree_cur SET c_parent = 'X' WHERE c_child = 'A';  
  286. UPDATE tree_cur SET c_parent = 'Y' WHERE c_child = 'C';  
  287.   
  288. COMMIT;  
  289.   
  290. EXEC p_tree_his_upd;  
  291. EXEC p_tree_his_upd;  
  292. EXEC p_tree_his_upd;  
  293.   
  294. SELECT * FROM tree_his;  
  295.   
  296.     SELECT *  
  297.       FROM tree_his  
  298.      WHERE exp_date = TO_DATE ('9999-12-31''yyyy-mm-dd')  
  299. START WITH p_id IS NULL  
  300. CONNECT BY PRIOR id = p_id;  
  301.   
  302. /*** 删除子树 ***/  
  303. DELETE FROM tree_cur WHERE c_child = 'J';  
  304. DELETE FROM tree_cur WHERE c_child = 'K';  
  305. DELETE FROM tree_cur WHERE c_child = 'D';  
  306.   
  307. COMMIT;  
  308.   
  309. EXEC p_tree_his_upd;  
  310. EXEC p_tree_his_upd;  
  311. EXEC p_tree_his_upd;  
  312.   
  313. SELECT * FROM tree_his;  
  314.   
  315.     SELECT *  
  316.       FROM tree_his  
  317.      WHERE exp_date = TO_DATE ('9999-12-31''yyyy-mm-dd')  
  318. START WITH p_id IS NULL  
  319. CONNECT BY PRIOR id = p_id;  
0 0