zoukankan      html  css  js  c++  java
  • Oracle 递归

      当对象存在父节点、子节点时,通过特定的方式获取父节点、子节点数据构建树状结构或其它形式结构时,通常都会使用递归,如:一个公司有多个部门、每个部门下可能有多个小部门,小部门下面又有组….为了数据容易管理和维护,通过构建合适的表结构存储这些数据,以下示例以省市县为例学习了解递归:
    1.创建存储省市县数据表:

       1:  create table tb_distree
       2:  (
       3:  id number,
       4:  name varchar2(300),
       5:  pid number
       6:  )
       7:  /
       8:   remark 添加主外键
       9:  alter table tb_distree add (
      10:  constraints pk_id primary key(id),
      11:  constraints fk_pid foreign key(pid) references tb_distree(id)
      12:  )
      13:  /

    2.初始化数据:

       1:  insert into tb_distree(id,name) values(1,'云南省');
       2:  insert into tb_distree(id,name,pid) values(2,'昆明市',1);
       3:  insert into tb_distree(id,name,pid) values(3,'临沧市',1);
       4:  insert into tb_distree(id,name,pid) values(4,'丽江市',1);
       5:  insert into tb_distree(id,name,pid) values(5,'云县',3);
       6:  insert into tb_distree(id,name,pid) values(6,'凤庆',3);
       7:  insert into tb_distree(id,name,pid) values(7,'幸福',3);
       8:  insert into tb_distree(id,name,pid) values(8,'盘龙区',2);
       9:  insert into tb_distree(id,name,pid) values(9,'五华区',2);
      10:  insert into tb_distree(id,name,pid) values(10,'西山区',2);

    3.递归查询语法:

       1:  select column... from table_name 
       2:  where ....  过滤条件
       3:  start with ...  递归开始点
       4:  connect by prior .... 优先级

    4.递归查询数据:
    4.1 从父节点开始查询出所有父节点和子节点:

    SQL> select id,name,pid from tb_distree start with pid is null connect by prior id=pid;
     
            ID NAME                PID
    ---------- ------------ ----------
             1 云南省
             2 昆明市                1
             8 盘龙区                2
             9 五华区                2
            10 西山区                2
             3 临沧市                1
             5 云县                  3
             6 凤庆                  3
             7 幸福                  3
             4 丽江市                1
     
    10 rows selected.

    4.2 查询某个节点的父节点:

     SQL> select id,name,pid from tb_distree start with name='云县' connect by prior pid=id;
     
            ID NAME                PID
    ---------- ------------ ----------
             5 云县                  3
             3 临沧市                1
             1 云南省

    在上例中"云县"属于"临沧市","临沧市"属于"云南省";对于从父节点递归到子节点,优先级条件为子节点id等于父节点id;对于从子节点到父节点递归,方向刚好相反;
    4.3 通过层次查询出父节点和某个子节点:

    SQL> select id,name,pid,level from tb_distree where level in(1,2) start with pid is null connect by prior id=pid;
     
            ID NAME                PID      LEVEL
    ---------- ------------ ---------- ----------
             1 云南省                           1
             2 昆明市                1          2
             3 临沧市                1          2
             4 丽江市                1          2

    层次也很重要,某些时候要修改某个节点父节点或子节点时会很有用;
    5. 递归查询效率:    

    SQL>select/*+ selectDG1 */ id,name,pid from tb_distree start with pid is null connect by prior id=pid;
     
    SQL> select sql_id,sql_text from v$sql where sql_text like '%selectDG1%' ;    
    SQL_ID          SQL_TEXT
    --------------- --------------------------------------------------
    2wnu324ga4n0y   select sql_id,sql_text from v$sql where sql_text l
                    ike '%selectDG1%'
     
    d4g89bucsbvzd   select/*+ selectDG1 */ id,name,pid from tb_distree
                     start with pid is null connect by prior id=pid
     
             
    SQL>select * from table(dbms_xplan.display_cursor('d4g89bucsbvzd',null,'advanced allstats last peeked_binds'));
    PLAN_TABLE_OUTPUT
    ------------------------------------------------------------------------------------------------------------
    SQL_ID  d4g89bucsbvzd, child number 0
    -------------------------------------
    select/*+ selectDG1 */ id,name,pid from tb_distree start with pid is
    null connect by prior id=pid
     
    Plan hash value: 1466399788
     
    ------------------------------------------------------------------------------------------------------------------------------------------------
    | Id  | Operation                               | Name       | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
    ------------------------------------------------------------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT                        |            |      1 |        |       |    18 (100)|          |     10 |00:00:00.01 |      22 |
     
    PLAN_TABLE_OUTPUT
    ----------------------------------------------------------------------------------------------------------------------------
    |*  1 |  CONNECT BY NO FILTERING WITH START-WITH|            |      1 |        |       |            |          |     10 |00:00:00.01 |      22 |
    |   2 |   TABLE ACCESS FULL                     | TB_DISTREE |      1 |     10 |  1780 |    17   (0)| 00:00:01 |     10 |00:00:00.01 |      22 |
    ------------------------------------------------------------------------------------------------------------------------------------------------
     
    Query Block Name / Object Alias (identified by operation id):
    -------------------------------------------------------------
     
       1 - SEL$1
       2 - SEL$2 / TB_DISTREE@SEL$2
     
    Outline Data
     
    PLAN_TABLE_OUTPUT
    --------------------------------------------------------------------------------------------------------------------------------------------------
      /*+
          BEGIN_OUTLINE_DATA
          IGNORE_OPTIM_EMBEDDED_HINTS
          OPTIMIZER_FEATURES_ENABLE('11.2.0.3')
          DB_VERSION('11.2.0.3')
          ALL_ROWS
          OUTLINE_LEAF(@"SEL$2")
          OUTLINE_LEAF(@"SEL$3")
          OUTLINE_LEAF(@"SEL$4")
     
    PLAN_TABLE_OUTPUT
    ---------------------------------------------------------------------------------------------------------------------------------------------------
          OUTLINE_LEAF(@"SET$1")
          OUTLINE_LEAF(@"SEL$1")
          NO_ACCESS(@"SEL$1" "connect$_by$_work$_set$_006"@"SEL$1")
          NO_CONNECT_BY_FILTERING(@"SEL$1")
          CONNECT_BY_COMBINE_SW(@"SEL$1")
          FULL(@"SEL$4" "TB_DISTREE"@"SEL$4")
          FULL(@"SEL$3" "connect$_by$_pump$_002"@"SEL$3")
          FULL(@"SEL$3" "TB_DISTREE"@"SEL$3")
          LEADING(@"SEL$3" "connect$_by$_pump$_002"@"SEL$3" "TB_DISTREE"@"SEL$3")
          USE_HASH(@"SEL$3" "TB_DISTREE"@"SEL$3")
          FULL(@"SEL$2" "TB_DISTREE"@"SEL$2")
     
    PLAN_TABLE_OUTPUT
    ----------------------------------------------------------------------------------------------------------------------------------------------
          END_OUTLINE_DATA
      */
     
    Predicate Information (identified by operation id):
    ---------------------------------------------------
     
       1 - access("PID"=PRIOR NULL)
           filter("PID" IS NULL)
           
     10046 trace:
    Rows (1st) Rows (avg) Rows (max)  Row Source Operation
     675 ---------- ---------- ----------  ---------------------------------------------------
     676         10         10         10  CONNECT BY NO FILTERING WITH START-WITH (cr=22 pr=0 pw=0 time=269 us)
     677         10         10         10   TABLE ACCESS FULL TB_DISTREE (cr=22 pr=0 pw=0 time=118 us cost=17 size=1780 card=10)
     678 
     679 
     680 Elapsed times include waiting on following events:
     681   Event waited on                             Times   Max. Wait  Total Waited
     682   ----------------------------------------   Waited  ----------  ------------
     683   row cache lock                                  3        0.00          0.00
     684   Disk file operations I/O                        1        0.00          0.00
     685   db file sequential read                         3        0.03          0.04
     686   SQL*Net message to client                       2        0.00          0.00
     687   SQL*Net message from client                     2        0.00          0.00                                                                                                      
     688 ********************************************************************************              

    在递归表上创建索引是没有用的,都必须进行全表扫描,当然通常这样的表也不会很大,如果数据量的确很大,建议将表中的节点拆分成多个表提高效率;

  • 相关阅读:
    Java学习开篇
    《我的姐姐》
    世上本无事,庸人自扰之
    这48小时
    补觉
    淡定
    es java api 设置index mapping 报错 mapping source must be pairs of fieldnames and properties definition.
    java mongodb groupby分组查询
    linux 常用命令
    mongodb too many users are authenticated
  • 原文地址:https://www.cnblogs.com/lanston/p/3750552.html
Copyright © 2011-2022 走看看