`

递归函数

阅读更多

oracle start with connect by 用法

 

oracle中 connect by prior 递归算法 

Oracle中start with...connect by prior子句用法 connect by 是结构化查询中用到的,其基本语法是: 
select ... from tablename start with 条件1 
connect by 条件2 
where 条件3; 
例: 
select * from table 
start with org_id = 'HBHqfWGWPy' 
connect by prior org_id = parent_id; 

     简单说来是将一个树状结构存储在一张表里,比如一个表中存在两个字段: 
org_id,parent_id那么通过表示每一条记录的parent是谁,就可以形成一个树状结构。 
     用上述语法的查询可以取得这棵树的所有记录。 
     其中: 
     条件1 是根结点的限定语句,当然可以放宽限定条件,以取得多个根结点,实际就是多棵树。 
     条件2 是连接条件,其中用PRIOR表示上一条记录,比如 CONNECT BY PRIOR org_id = parent_id就是说上一条记录的org_id 是本条记录的parent_id,即本记录的父亲是上一条记录。 
     条件3 是过滤条件,用于对返回的所有记录进行过滤。 

     简单介绍如下: 
     早扫描树结构表时,需要依此访问树结构的每个节点,一个节点只能访问一次,其访问的步骤如下: 
     第一步:从根节点开始; 
     第二步:访问该节点; 
     第三步:判断该节点有无未被访问的子节点,若有,则转向它最左侧的未被访问的子节,并执行第二步,否则执行第四步; 
     第四步:若该节点为根节点,则访问完毕,否则执行第五步; 
     第五步:返回到该节点的父节点,并执行第三步骤。 

     总之:扫描整个树结构的过程也即是中序遍历树的过程。 

     1. 树结构的描述 
树结构的数据存放在表中,数据之间的层次关系即父子关系,通过表中的列与列间的关系来描述,如EMP表中的EMPNO和 MGR。EMPNO表示该雇员的编号,MGR表示领导该雇员的人的编号,即子节点的MGR值等于父节点的EMPNO值。在表的每一行中都有一个表示父节点 的MGR(除根节点外),通过每个节点的父节点,就可以确定整个树结构。 
在SELECT命令中使用CONNECT BY 和蔼START WITH 子句可以查询表中的树型结构关系。其命令格式如下: 
SELECT 。。。 
CONNECT BY {PRIOR 列名1=列名2|列名1=PRIOR 裂名2} 
[START WITH]; 
其中:CONNECT BY子句说明每行数据将是按层次顺序检索,并规定将表中的数据连入树型结构的关系中。PRIORY 运算符必须放置在连接关系的两列中某一个的前面。对于节点间的父子关系,PRIOR运算符在一侧表示父节点,在另一侧表示子节点,从而确定查找树结构是的 顺序是自顶向下还是自底向上。在连接关系中,除了可以使用列名外,还允许使用列表达式。START WITH 子句为可选项,用来标识哪个节点作为查找树 型结构的根节点。若该子句被省略,则表示所有满足查询条件的行作为根节点。 
START WITH: 不但可以指定一个根节点,还可以指定多个根节点。 
2. 关于PRIOR 
运算符PRIOR被放置于等号前后的位置,决定着查询时的检索顺序。 
PRIOR被置于CONNECT BY子句中等号的前面时,则强制从根节点到叶节点的顺序检索,即由父节点向子节点方向通过树结构,我们称之为自顶向下的方式。如: 
CONNECT BY PRIOR EMPNO=MGR 
PIROR运算符被置于CONNECT BY 子句中等号的后面时,则强制从叶节点到根节点的顺序检索,即由子节点向父节点方向通过树结构,我们称之为自底向上的方式。例如: 
CONNECT BY EMPNO=PRIOR MGR 
在这种方式中也应指定一个开始的节点。 
3. 定义查找起始节点 
     在自顶向下查询树结构时,不但可以从根节点开始,还可以定义任何节点为起始节点,以此开始向下查找。这样查找的结果就是以该节点为开始的结构树的一枝。 
4.使用LEVEL 
在具有树结构的表中,每一行数据都是树结构中的一个节点,由于节点所处的层次位置不同,所以每行记录都可以有一个层号。层号根据节点与根节点的距离确定。不论从哪个节点开始,该起始根节点的层号始终为1,根节点的子节点为2, 依此类推。 
5.节点和分支的裁剪 
在对树结构进行查询时,可以去掉表中的某些行,也可以剪掉树中的一个分支,使用WHERE子句来限定树型结构中的单个节点,以去掉树中的单个节点,但它却不影响其后代节点(自顶向下检索时)或前辈节点(自底向顶检索时)。 
6.排序显示 
象在其它查询中一样,在树结构查询中也可以使用ORDER BY 子句,改变查询结果的显示顺序,而不必按照遍历树结构的顺序 

 

----------------------------------------------------------------------------------------------------------

oracle 提供了start with connect by 语法结构可以实现递归查询。

1. 一个简单举例:
SQL> select *  from test;

BILL_MONTH           DAY_NUMBER MSISDN
-------------------- ---------- --------------------
200803                        1 13800
200803                        3 13800
200803                        2 13800
200803                        2 13801
200803                        4 13804
200803                        5 13804
200803                        7 13804
200803                        8 13804
200803                        6 13802
200803                        6 13801
200803                        7 13801
200803                        8 13801

12 rows selected

SQL>
SQL> select * from test
2       start with day_number=1
3       connect by  prior day_number=day_number-1 and prior msisdn= msisdn
4      ;

BILL_MONTH           DAY_NUMBER MSISDN
-------------------- ---------- --------------------
200803                        1 13800
200803                        2 13800
200803                        3 13800

SQL>


上面的语句查找出了从1开始,并且day_number 逐渐+1 递增的,并且 msisdn 相同的哪些个数据.


2. start with  connect by 语法结构
如上面说看到的 例子, 其语法结构为  start with condition  connect by  condition (含 prior 关键字)
start with conditon 给出的seed 数据的范围, connect by  后面给出了递归查询的条件,prior 关键字表示父数据,prior 条件表示子数据需要满足父数据的什么条件。

在下面的这个start with connect by 结构中,就表示 查找出了从1开始,并且day_number 逐渐+1 递增的,并且 msisdn 相同的那些个数据.

start with day_number=1
connect by  prior day_number=day_number-1 and prior msisdn= msisdn

3.  执行计划
对于这个特殊的语法结构,我们来看看它的执行计划。
通过下面的执行计划,我们可以看出,对于简单的访问一个对象的递归查询,实际上oracle 要三次访问要查询的对象。因此,这一个告诉我们,在使用递归查询时,一定要谨慎,因为即使原表数据不多,但是三倍的访问喜爱来,代价也会很大。

SQL> explain plan for

2   select * from  test
3    --where  bill_month='200803'
4    start with day_number=1
5    connect by  prior day_number=day_number-1 and prior msisdn= msisdn
6  ;

Explained

SQL> select *  from  table( dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
-------------------------------------------------------------------------
| Id  | Operation                 |  Name       | Rows  | Bytes | Cost  |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT          |             |       |       |       |
|*  1 |  CONNECT BY WITH FILTERING|             |       |       |       |
|*  2 |   FILTER                  |             |       |       |       |
|   3 |    TABLE ACCESS FULL      | TEST        |       |       |       |
|   4 |   NESTED LOOPS            |             |       |       |       |
|   5 |    BUFFER SORT            |             |       |       |       |
|   6 |     CONNECT BY PUMP       |             |       |       |       |
|*  7 |    TABLE ACCESS FULL      | TEST        |       |       |       |
|   8 |   TABLE ACCESS FULL       | TEST        |       |       |       |
-------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("TEST"."DAY_NUMBER"=1)
2 - filter("TEST"."DAY_NUMBER"=1)

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
7 - filter("TEST"."MSISDN"=NULL AND "TEST"."DAY_NUMBER"-1=NULL)
Note: rule based optimization

23 rows selected

SQL>


另外,发现了在含有其他条件的递归中,是先处理所有的递归查询,最后才用加入的条件过滤.
请看下面的例子。
和上面的执行计划对比下我们可以知道,加入条件   where  bill_month='200803' 后,实际上却是在递归完成后,最后才执行的    1 - filter("TEST"."BILL_MONTH"='200803') 。

所以,为了确保语句的性能,不要直接加入条件在start with connect by 结构中,而是要想办法将原表的数据控制住。这个可以采用子查 询的办法,或者使用临时表等(最好采用临时表,将数据量从本源上控制住;因为从子查询的执行计划我们可以看到,它每次也都是访问全表,再用条件过滤,要重 复三次,不是一次过滤就够了).

--直接加入条件后的执行计划
SQL> explain plan for

2   select * from  test
3    where  bill_month='200803'
4    start with day_number=1
5    connect by  prior day_number=day_number-1 and prior msisdn= msisdn
6  ;

Explained

SQL> select *  from  table( dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------
| Id  | Operation                  |  Name       | Rows  | Bytes | Cost  |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT           |             |       |       |       |
|*  1 |  FILTER                    |             |       |       |       |
|*  2 |   CONNECT BY WITH FILTERING|             |       |       |       |
|*  3 |    FILTER                  |             |       |       |       |
|   4 |     TABLE ACCESS FULL      | TEST        |       |       |       |
|   5 |    NESTED LOOPS            |             |       |       |       |
|   6 |     BUFFER SORT            |             |       |       |       |
|   7 |      CONNECT BY PUMP       |             |       |       |       |
|*  8 |     TABLE ACCESS FULL      | TEST        |       |       |       |
|   9 |    TABLE ACCESS FULL       | TEST        |       |       |       |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("TEST"."BILL_MONTH"='200803')

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
2 - filter("TEST"."DAY_NUMBER"=1)
3 - filter("TEST"."DAY_NUMBER"=1)
8 - filter("TEST"."MSISDN"=NULL AND "TEST"."DAY_NUMBER"-1=NULL)
Note: rule based optimization

25 rows selected

SQL>


--使用子查询,将过滤条件嵌在子查询中
SQL> explain plan for

2  select * from (select * from test
3        where  bill_month='200803')
4       start with day_number=1
5       connect by  prior day_number=day_number-1 and prior msisdn= msisdn
6      ;

Explained

SQL> select *  from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
-------------------------------------------------------------------------
| Id  | Operation                 |  Name       | Rows  | Bytes | Cost  |
-------------------------------------------------------------------------
|   0 | SELECT STATEMENT          |             |       |       |       |
|*  1 |  CONNECT BY WITH FILTERING|             |       |       |       |
|*  2 |   FILTER                  |             |       |       |       |
|*  3 |    TABLE ACCESS FULL      | TEST        |       |       |       |
|   4 |   NESTED LOOPS            |             |       |       |       |
|   5 |    BUFFER SORT            |             |       |       |       |
|   6 |     CONNECT BY PUMP       |             |       |       |       |
|*  7 |    TABLE ACCESS FULL      | TEST        |       |       |       |
|*  8 |   TABLE ACCESS FULL       | TEST        |       |       |       |
-------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("TEST"."DAY_NUMBER"=1)
2 - filter("TEST"."DAY_NUMBER"=1)

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
3 - filter("TEST"."BILL_MONTH"='200803')
7 - filter("TEST"."BILL_MONTH"='200803' AND "TEST"."MSISDN"=NULL AND
"TEST"."DAY_NUMBER"-1=NULL)
8 - filter("TEST"."BILL_MONTH"='200803')
Note: rule based optimization

26 rows selected

SQL>



4. 实际中 递归查询的使用。

问题:
数据库里有字段day_number,msisdn。如何写月度连续3天有记录的手机号?表结构如下:

id   bill_month   day_number     msisdn
1      200803      1           13800000000
2      200803      1           130137.....
3      200803      2           13800000000
4      200803      3           13800000000
..............................

表中3月份连续3天有记录的纪录就是1380000000。请问如何写这样的sql?


解决方案:
SQL> create  table   test ( bill_month varchar2(20),day_number number ,msisdn varchar2(20));

Table created

SQL> insert into  test values ( '200803',1,'13800');

1 row inserted

SQL> insert into  test values ( '200803',3,'13800');

1 row inserted

SQL> insert into  test values ( '200803',2,'13800');

1 row inserted

SQL> insert into  test values ( '200803',2,'13801');

1 row inserted

SQL> insert into  test values ( '200803',4,'13804');

1 row inserted

SQL> insert into  test values ( '200803',5,'13804');

1 row inserted

SQL> commit;

Commit complete

SQL> select *  from test;

BILL_MONTH           DAY_NUMBER MSISDN
-------------------- ---------- --------------------
200803                        1 13800
200803                        3 13800
200803                        2 13800
200803                        2 13801
200803                        4 13804
200803                        5 13804

6 rows selected

SQL>
SQL> select distinct  msisdn  from test  a
2  where  bill_month='200803'
3  and exists
4  ( select msisdn from  test
5    where  bill_month='200803' and msisdn=a.msisdn
6    start with day_number=a.day_number
7    connect by  prior day_number=day_number-1 and prior msisdn= msisdn
8    group by msisdn
9    having count(*)>=3
10    );

MSISDN
--------------------
13800


SQL> select *  from test;

BILL_MONTH           DAY_NUMBER MSISDN
-------------------- ---------- --------------------
200803                        1 13800
200803                        3 13800
200803                        2 13800
200803                        2 13801
200803                        4 13804
200803                        5 13804

6 rows selected

SQL> insert into  test values ( '200803',7,'13804');

1 row inserted

SQL> insert into  test values ( '200803',8,'13804');

1 row inserted

SQL> insert into  test values ( '200803',6,'13802');

1 row inserted

SQL> insert into  test values ( '200803',6,'13801');

1 row inserted

SQL> insert into  test values ( '200803',7,'13801');

1 row inserted

SQL> insert into  test values ( '200803',8,'13801');

1 row inserted

SQL> select *  from test;

BILL_MONTH           DAY_NUMBER MSISDN
-------------------- ---------- --------------------
200803                        1 13800
200803                        3 13800
200803                        2 13800
200803                        2 13801
200803                        4 13804
200803                        5 13804
200803                        7 13804
200803                        8 13804
200803                        6 13802
200803                        6 13801
200803                        7 13801
200803                        8 13801

12 rows selected

SQL> commit;

Commit complete

SQL>
SQL> select distinct  msisdn  from test  a
2  where  bill_month='200803'
3  and exists
4  ( select msisdn from  test
5    where  bill_month='200803' and msisdn=a.msisdn
6    start with day_number=a.day_number
7    connect by  prior day_number=day_number-1 and prior msisdn= msisdn
8    group by msisdn
9    having count(*)>=3
10    );

MSISDN
--------------------
13800
13801

SQL>

分享到:
评论

相关推荐

    C通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数。

    C通过运行时堆栈支持递归函数的实现。递归函数就是直接或间接调用自身的函数。 许多教科书都把计算机阶乘和菲波那契数列用来说明递归,非常不幸我们可爱的著名的老潭老师的《C语言程序设计》一书中就是从阶乘的计算...

    Oracle 递归函数介绍

    Oracle 递归函数介绍 Oracle 递归函数是一种特殊的PL/SQL函数,可以用于解决复杂的树形结构查询问题。递归函数可以自我调用,以便遍历树形结构的每个节点,直到达到停止条件。 在 Oracle 中,递归函数的定义语法...

    5.6 递归思想和递归函数1

    递归函数是实现递归思想的一种方式,通常在函数内部调用自身来解决复杂问题。本节将深入探讨递归思想和递归函数的概念,并通过几个具体的Python示例来阐述其工作原理和应用。 首先,理解递归的关键在于明确两个核心...

    Python语言基础:递归函数.pptx

    在编程领域,递归函数是一种基于函数自我调用来解决问题的策略。在Python中,递归函数的定义简单,逻辑清晰,使得复杂问题的解决变得直观。递归函数的关键在于每个递归调用都必须向基本情况靠近,即最终会达到一个不...

    递归函数例子8个.rar

    在编程领域,递归函数是一种基于自我调用的函数设计技术,它在处理特定问题时,尤其是涉及到数据结构如树和图的操作时,显得尤为重要。本压缩包包含8个递归函数的例子,覆盖了多种递归应用,让我们逐一探讨这些递归...

    数据结构:栈的应用-递归函数转非递归函数

    总结一下,通过使用数据结构中的栈,我们可以将效率较低的递归函数转换为非递归函数,提高计算效率,减少内存消耗,防止堆栈溢出。在实际编程中,尤其是在处理大数据量或需要高效运行的算法时,这样的优化是非常重要...

    递归函数示意图.pdf

    递归函数是计算机科学中的一种基础概念,它的基本思想是函数直接或间接地调用自身。在上述内容中,首先展示了一个简单递归函数的示例,然后又通过添加辅助函数进行了尾递归优化。 在简单递归函数的示例中,定义了一...

    嵌入式C语言培训-C编程基础-递归函数视频教程

    本教程“嵌入式C语言培训-C编程基础-递归函数视频教程”聚焦于C语言的一个关键特性——递归函数。递归是编程中的一个强大工具,能够简化复杂问题的解决方案,但它也需要程序员有深入的理解才能正确使用。 递归函数...

    计算递归函数调用次数

    在编程领域,递归函数是一种强大的工具,它通过自身调用来解决复杂问题。递归的基本原理是将大问题分解为相同或相似的小问题,并通过解决这些小问题来达到解决整个问题的目的。本主题关注的是如何计算递归函数的调用...

    delphi递归函数应用

    Delphi,作为一款流行的Object Pascal编程环境,同样支持递归函数的使用。本篇文章将详细探讨Delphi中的递归函数及其应用。 首先,我们要理解递归的基本概念。递归是指一个函数或过程通过调用自身来完成任务。这种...

    利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来。

    利用递归函数调用方式,将所输入的5个字符,以相反顺序打印出来。

    c++递归函数基本代码.zip

    在“c++递归函数基本代码.zip”压缩包中,可能包含了若干个示例,用于展示如何在C++中实现递归。 首先,理解递归的基本原理至关重要。递归函数必须满足两个条件:一是存在基本情况(base case),即问题可以直接...

    省市县递归函数

    省市县递归函数

    递归函数两个例子教程(VB6.0代码编写)

    在编程领域,递归函数是一种强大的工具,它通过调用自身来解决问题或执行任务。VB6.0(Visual Basic 6.0)虽然是一款较老的编程环境,但仍然广泛用于教学和某些遗留系统的维护。本教程将通过两个具体的例子深入讲解...

    第2章 原始递归函数

    由原始递归函数经过合成或原始递归得到的函数仍是原始递归函数.

    递归函数演示

    二是理解和调试递归函数可能较为困难,因为它们涉及的逻辑通常比非递归函数更为抽象。因此,在实际编程中,我们需要权衡递归的优点和缺点,选择最适合问题的解决方案。 总结来说,递归是计算机科学中的一个重要概念...

    Python中递归函数的使用示例

    使用环境:需要先安装PyCharm(请自己百度下载安装),以及然后官网上下载Python 2.7版本,以及Python 3.7版本后,安装在自己的电脑上。 使用步骤: ...目的:帮助理解递归函数在Python中的具体使用。

    使用递归函数在矩阵中寻找路径

    在这个场景中,我们采用了一种称为“回溯法”的策略,配合递归函数来找到从起点到终点的有效路径。本文将深入探讨回溯法的概念,递归函数的应用,以及如何将两者结合解决迷宫问题。 首先,理解回溯法是关键。回溯法...

    C语言递归函数设计

    C语言递归函数设计,如何使用递归函数进行算法计算,这样可以提高程序的质量

    Python 递归函数详解及实例

    Python 递归函数 如果一个函数体直接或者间接调用自己,那么这个函数就称为递归函数.也就是说,递归函数体的执行过程中可能会返回去再次调用该函数.在python里,递归函数不需要任何特殊的语法,但是它需要...

Global site tag (gtag.js) - Google Analytics