`
Tiwen
  • 浏览: 86193 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

ORACLE层次查询技巧

 
阅读更多

ORACLE层次查询技巧

create table emp_hire as

selectempno,mgr,ename from emp

select * from emp_hire

EMPNO

MGR

ENAME

5555

7900

ggg

7369

7902

SMITH

7499

7698

ALLEN

7521

7698

WARD

7566

7839

JONES

7654

7698

MA & RTIN

7698

7839

BLAKE

7782

7839

CLARK

7788

7566

SCOTT

7839

KING

7844

7698

TURNER

7900

7698

JAMES

7902

7566

FORD

7934

7782

MILLER

7876

7788

ADAMS

这些数据存在着层次关系

select

lpad('*',level,'*')||e.ename ename,

e.empno,

mgr fa_id,

(select ename from emp_hire where empno=e.mgr) fa_name

from emp_hiree

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

ENAME

EMPNO

FA_ID

FA_NAME

*KING

7839

**JONES

7566

7839

KING

***SCOTT

7788

7566

JONES

****ADAMS

7876

7788

SCOTT

***FORD

7902

7566

JONES

****SMITH

7369

7902

FORD

**BLAKE

7698

7839

KING

***ALLEN

7499

7698

BLAKE

***WARD

7521

7698

BLAKE

***MA & RTIN

7654

7698

BLAKE

***TURNER

7844

7698

BLAKE

***JAMES

7900

7698

BLAKE

****ggg

5555

7900

JAMES

**CLARK

7782

7839

KING

***MILLER

7934

7782

CLARK




其中
start with -- this identifies all LEVEL=1 nodes in the tree

connect by -- describes how to walk from the parent nodes above to their children and their childrens children.

层次是一棵树, 又如同一个家族图谱

每一个子节电只有一个父节点;

每一个分支,最末端是叶节点;

SELECT

ename Employee,

CONNECT_BY_ISLEAF IsLeaf,

LEVEL lev,

SYS_CONNECT_BY_PATH(ename, '/') Path

FROM emp

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

EMPLOYEE

ISLEAF

LEV

PATH

KING

0

1

/KING

JONES

0

2

/KING/JONES

SCOTT

0

3

/KING/JONES/SCOTT

ADAMS

1

4

/KING/JONES/SCOTT/ADAMS

FORD

0

3

/KING/JONES/FORD

SMITH

1

4

/KING/JONES/FORD/SMITH

BLAKE

0

2

/KING/BLAKE

ALLEN

1

3

/KING/BLAKE/ALLEN

WARD

1

3

/KING/BLAKE/WARD

MA & RTIN

1

3

/KING/BLAKE/MA & RTIN

TURNER

1

3

/KING/BLAKE/TURNER

JAMES

0

3

/KING/BLAKE/JAMES

ggg

1

4

/KING/BLAKE/JAMES/ggg

CLARK

0

2

/KING/CLARK

MILLER

1

3

/KING/CLARK/MILLER

检查一个层次是否存在闭循环

CONNECT_BY_ISCYCLE

找出根节点

CONNECT_BY_ROOT

SELECT

ename Employee,

CONNECT_BY_ISCYCLE,

CONNECT_BY_ROOT ename

FROM emp

START WITH MGR IS NULL

CONNECT BY NOCYCLE PRIOR EMPNO = MGR

EMPLOYEE

CONNECT_BY_ISCYCLE

CONNECT_BY_ROOTENAME

KING

0

KING

JONES

0

KING

SCOTT

0

KING

ADAMS

0

KING

FORD

0

KING

SMITH

0

KING

BLAKE

0

KING

ALLEN

0

KING

WARD

0

KING

MA & RTIN

0

KING

TURNER

0

KING

JAMES

0

KING

ggg

0

KING

CLARK

0

KING

MILLER

0

KING

层次查询的过滤条件

SELECT

ename Employee,

CONNECT_BY_ISLEAF IsLeaf,

LEVEL lev,

SYS_CONNECT_BY_PATH(ename, '/') Path

FROM emp

where level<3

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

Restriction on LEVEL in WHERE Clauses In a [NOT] IN condition in a WHERE clause, if the right-hand side of the condition is asubquery, you cannot use LEVEL on the left-hand sideof the condition. However, you can specify LEVEL in a subquery of the FROM clause to achieve the same result. For example, thefollowing statement is not valid:

SELECT employee_id, last_name FROM employees

WHERE (employee_id,LEVEL)

IN (SELECTemployee_id, 2 FROM employees)

START WITHemployee_id = 2

CONNECT BY PRIORemployee_id = manager_id;

But the following statement is valid because it encapsulates the querycontaining the

LEVEL information in the FROM clause:

SELECT v.employee_id, v.last_name, v.lev

FROM

(SELECT employee_id,last_name, LEVEL lev

FROM employees v

START WITHemployee_id = 100

CONNECT BY PRIORemployee_id = manager_id) v

WHERE(v.employee_id, v.lev) IN

(SELECT employee_id,2 FROM employees);

SIBLINGS的排序

SELECT

ename Employee,

CONNECT_BY_ISLEAF IsLeaf,

LEVEL lev,

SYS_CONNECT_BY_PATH(ename, '/') Path

FROM emp

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

ORDER SIBLINGS BY ename desc

EMPLOYEE

ISLEAF

LEV

PATH

KING

0

1

/KING

JONES

0

2

/KING/JONES

SCOTT

0

3

/KING/JONES/SCOTT

ADAMS

1

4

/KING/JONES/SCOTT/ADAMS

FORD

0

3

/KING/JONES/FORD

SMITH

1

4

/KING/JONES/FORD/SMITH

CLARK

0

2

/KING/CLARK

MILLER

1

3

/KING/CLARK/MILLER

BLAKE

0

2

/KING/BLAKE

WARD

1

3

/KING/BLAKE/WARD

TURNER

1

3

/KING/BLAKE/TURNER

MA & RTIN

1

3

/KING/BLAKE/MA & RTIN

JAMES

0

3

/KING/BLAKE/JAMES

ggg

1

4

/KING/BLAKE/JAMES/ggg

ALLEN

1

3

/KING/BLAKE/ALLEN

注意:ORDER SIBLINGS By一定与start with 与 connect by一起使用

检查树是否有闭循环

SELECT last_name"Employee", CONNECT_BY_ISCYCLE "Cycle",

LEVEL, SYS_CONNECT_BY_PATH(last_name, '/')"Path"

FROM employees

WHERE level <= 3AND department_id = 80

START WITH last_name= 'King'

CONNECT BY NOCYCLEPRIOR employee_id = manager_id AND LEVEL <= 4;

Employee

Cycle

LEVEL

Path

King

0

1

/King

Russell

0

2

/King/Russell

Tucker

0

3

/King/Russell/Tucker

Bernstein

0

3

/King/Russell/Bernstein

Hall

0

3

/King/Russell/Hall

Olsen

0

3

/King/Russell/Olsen

Cambrault

0

3

/King/Russell/Cambrault

Tuvault

0

3

/King/Russell/Tuvault

Partners

0

2

/King/Partners

King

0

3

/King/Partners/King

层次查询的累计运算

将非叶节点的度量sal置为空

update emp_hireset sal=null

where empno in

(

select empno from

(

SELECT

empno,

CONNECT_BY_ISLEAF IsLeaf,

LEVEL lev,

SYS_CONNECT_BY_PATH(ename, '/') Path

FROM emp

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

)

where isleaf=0

)

察看数据

SELECT

empno,

CONNECT_BY_ISLEAF IsLeaf,

LEVEL lev,

SYS_CONNECT_BY_PATH(ename, '/') Path,

sal

FROM emp_hire

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

EMPNO

ISLEAF

LEV

PATH

SAL

7839

0

1

/KING

7566

0

2

/KING/JONES

7788

0

3

/KING/JONES/SCOTT

7876

1

4

/KING/JONES/SCOTT/ADAMS

1100.00

7902

0

3

/KING/JONES/FORD

7369

1

4

/KING/JONES/FORD/SMITH

800.00

7698

0

2

/KING/BLAKE

7499

1

3

/KING/BLAKE/ALLEN

1600.00

7521

1

3

/KING/BLAKE/WARD

1250.00

7654

1

3

/KING/BLAKE/MA & RTIN

1250.00

7844

1

3

/KING/BLAKE/TURNER

1500.00

7900

0

3

/KING/BLAKE/JAMES

5555

1

4

/KING/BLAKE/JAMES/ggg

0.00

7782

0

2

/KING/CLARK

7934

1

3

/KING/CLARK/MILLER

1300.00

select

sum(sal),

sum(power(0.5,(level-1))*sal)

from emp_hire

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

SUM(SAL)

SUM(POWER(0.5,(LEVEL-1))*SAL)

8800

1962.5

我们不能用以下的方法计算累计值

select

SYS_CONNECT_BY_PATH(ename, '/') Path, sum(sal),

sum(power(0.5,(level-1))*sal)

from emp_hire

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

group by Path

我们可以找出一个节点的所有子孙节点,以及这些节点所在的level

select

empno,

SYS_CONNECT_BY_PATH(ename, '/') Path, sal,

--,sum(power(0.5,(level-1))*sal)

(

select sum(power(0.5,(level-1))*nvl(sal,0)) from emp_hire

start with empno=e.empno

connect by prior empno= mgr

) s_sal,

(

select sum(nvl(sal,0)) from emp_hire

start with empno=e.empno

connect by prior empno= mgr

) s1_sal

from emp_hiree

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

EMPNO

PATH

SAL

S_SAL

S1_SAL

7839

/KING

1962.5

8800

7566

/KING/JONES

475

1900

7788

/KING/JONES/SCOTT

550

1100

7876

/KING/JONES/SCOTT/ADAMS

1100.00

1100

1100

7902

/KING/JONES/FORD

400

800

7369

/KING/JONES/FORD/SMITH

800.00

800

800

7698

/KING/BLAKE

2800

5600

7499

/KING/BLAKE/ALLEN

1600.00

1600

1600

7521

/KING/BLAKE/WARD

1250.00

1250

1250

7654

/KING/BLAKE/MA & RTIN

1250.00

1250

1250

7844

/KING/BLAKE/TURNER

1500.00

1500

1500

7900

/KING/BLAKE/JAMES

0

0

5555

/KING/BLAKE/JAMES/ggg

0.00

0

0

7782

/KING/CLARK

650

1300

7934

/KING/CLARK/MILLER

1300.00

1300

1300

也可以通过以下过程实现:

create type myTable is table of varchar2(100);

CREATE OR REPLACE FUNCTION str_to_table (

string_in IN VARCHAR2 ,

delimiter_in IN VARCHAR2 DEFAULT ','

) RETURN myTable IS

v_wkg_str VARCHAR2 ( 32767 ) := string_in ||delimiter_in;

v_pos PLS_INTEGER ;

nt_return myTable :=myTable();

i_count pls_integer;

BEGIN

LOOP

v_pos :=INSTR(v_wkg_str,delimiter_in);

EXIT WHEN NVL(v_pos, 0 ) = 0orv_wkg_str=delimiter_in;

if TRIM (SUBSTR(v_wkg_str, 1 ,v_pos- 1 )) is not null then

nt_return. EXTEND ;

nt_return(nt_return. LAST ) := TRIM (SUBSTR(v_wkg_str, 1 ,v_pos- 1 ));

end if;

v_wkg_str :=SUBSTR(v_wkg_str,v_pos+ 1 );

END LOOP ;

RETURN nt_return;

END ;

declare

--create or replace type v2 is table of varchar2(2000)

c_path v2;

c_level v1;

c_empno v1;

v_pos integer;

v_string varchar2(2000);

begin

select

empno,SYS_CONNECT_BY_PATH(empno, '/') Path, level lev

bulk collect intoc_empno,c_path,c_level

from emp_hire

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR;

for i in 1..c_empno.count loop

v_string:='';

for j in 1..c_path.count loop

v_pos := INSTR(c_path(j),c_empno(i));

ifv_pos>0 andc_empno(i)<>c_empno(j) then

v_string:=v_string||'/'||c_empno(j);

end if;

end loop;

dbms_output.put_line(c_empno(i)||' '||v_string);

end loop;

end;

输出结果

7839/7566/7788/7876/7902/7369/7698/7499/7521/7654/7844/7900/5555/7782/7934

7566/7788/7876/7902/7369

7788 /7876

7876

7902 /7369

7369

7698/7499/7521/7654/7844/7900/5555

7499

7521

7654

7844

7900 /5555

5555

7782 /7934

7934

如果要计算累计结果则

declare

--create or replace type v2 is table of varchar2(2000)

c_path v2;

c_level v1;

c_empno v1;

c_salv1;

v_pos integer;

v_string varchar2(2000);

v_salnumber;

begin

select

empno,SYS_CONNECT_BY_PATH(empno, '/') Path, level lev, nvl(sal,0)

bulk collect intoc_empno,c_path,c_level,c_sal

from emp_hire

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR;

for i in 1..c_empno.count loop

v_string:='';

v_sal:=0;

for j in 1..c_path.count loop

v_pos := INSTR(c_path(j),c_empno(i));

if v_pos>0 then

if c_empno(i)<>c_empno(j) then

v_string:=v_string||'/'||c_empno(j);

end if;

v_sal:=v_sal+c_sal(j);

end if;

end loop;

dbms_output.put_line(c_empno(i)||' '||v_string||' '||v_sal);

end loop;

end;

7839 8800 /7566/7788/7876/7902/7369/7698/7499/7521/7654/7844/7900/5555/7782/7934

7566 1900 /7788/7876/7902/7369

7788 1100 /7876

7876 1100

7902 800 /7369

7369 800

7698 5600 /7499/7521/7654/7844/7900/5555

7499 1600

7521 1250

7654 1250

7844 1500

7900 0 /5555

5555 0

7782 1300 /7934

7934 1300

如果存在一定的累计规则

declare

--create or replace type v2 is table of varchar2(2000)

c_path v2;

c_level v1;

c_empno v1;

c_sal v1;

v_pos integer;

v_string varchar2(2000);

v_sal number;

begin

select

empno,SYS_CONNECT_BY_PATH(empno, '/') Path, level lev, nvl(sal,0)

bulk collect intoc_empno,c_path,c_level,c_sal

from emp_hire

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR;

for i in 1..c_empno.count loop

v_string:='';

v_sal:=0;

for j in 1..c_path.count loop

v_pos := INSTR(c_path(j),c_empno(i));

ifv_pos>0 then

ifc_empno(i)<>c_empno(j) then

v_string:=v_string||'/'||c_empno(j);

end if;

v_sal:=v_sal+power(0.5,(c_level(j)-c_level(i)))*c_sal(j);

end if;

end loop;

dbms_output.put_line(c_empno(i)||' '||' '||c_sal(i)||''||v_sal||' '||v_string);

end loop;

end;

78390 1962.5/7566/7788/7876/7902/7369/7698/7499/7521/7654/7844/7900/5555/7782/7934

75660 475 /7788/7876/7902/7369

77880 550/7876

78761100 1100

79020 400 /7369

7369800 800

76980 2800 /7499/7521/7654/7844/7900/5555

74991600 1600

75211250 1250

76541250 1250

78441500 1500

79000 0 /5555

55550 0

77820 650 /7934

79341300 1300

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

SELECT

empno,

ename Employee,

CONNECT_BY_ROOT ename,

level lev

FROM (select * from emp_hire where ename<>'KING')

START WITH MGR IS NULL

CONNECT BY NOCYCLE PRIOR EMPNO = MGR

层次查询的效率

Explain planfor

select

lpad('*',level,'*')||e.ename ename,

e.empno,

mgr fa_id

from emp_hire e

START WITH MGR IS NULL

CONNECT BY PRIOR EMPNO = MGR

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

Plan hashvalue: 2148023842

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

| Id | Operation | Name | Rows| Bytes | Cost (%CPU)| Time |

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

| 0 | SELECTSTATEMENT | |15 | 495 |3 (0)| 00:00:01 |

|* 1 | CONNECT BY NOFILTERING WITH START-WITH|| | | | |

| 2 | TABLE ACCESS FULL | EMP_HIRE | 15 |495 | 3 (0)| 00:00:01|

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

Predicate Information (identified byoperation id):

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

1- access("MGR"=PRIOR "EMPNO")

filter("MGR" IS NULL)

Note

-----

-dynamic sampling used for this statement

层次查询从本质上来说是递归运算,因此对于大的层次查询,可以分解为多个层次查询,从而减少计算量。

层次查询的副产品

产生自然数的查询

select rownum r from dual connect by level <= 100

层次向普通对称维度表的转换

分享到:
评论

相关推荐

    oracle高级查询技巧

    在Oracle数据库系统中,高级查询技巧是提升数据库管理员和程序员工作效率的关键。这些技巧不仅能够帮助我们获取更精确、更高效的数据,还能使数据处理过程更加灵活。以下是对"Oracle高级查询技巧"的详细阐述。 一、...

    Oracle层次查询功能的剖析.pdf

    Oracle层次查询功能是Oracle数据库系统中的一个重要特性,它在关系型数据库管理中为处理具有层级关系的数据提供了便利。本文主要探讨了如何利用Oracle的层次查询功能处理和展示类似树形结构的数据。 首先,层次结构...

    Oracle 实战SQL层次查询

    ### Oracle 实战SQL层次查询详解 #### 一、层次查询概念 ...以上介绍了Oracle中进行层次查询的基本方法和一些实用技巧。层次查询是处理复杂数据结构时非常有用的工具,熟练掌握这些技巧对于提高工作效率至关重要。

    ORACLE数据库维护技巧

    ### ORACLE数据库维护技巧详解 #### 一、引言 在日常工作中,Oracle数据库管理员(DBA)经常会遇到应用程序运行缓慢的问题。尽管从表面来看数据库的各项指标似乎都在正常范围内,但深层次的问题往往存在于I/O操作中。...

    oracle递归查询的例子

    ### Oracle 递归查询详解及实例 #### 一、引言 ...掌握这些技巧对于高效管理和查询复杂数据结构至关重要。在实际工作中,根据不同的需求灵活运用这些特性,可以极大地提高工作效率和解决问题的能力。

    Oracle sql查询当前月的所有日期

    - **`CONNECT BY`子句**:这是Oracle特有的一个子句,用于创建层次结构查询。在本例中,虽然没有明显的层次关系,但利用`CONNECT BY`可以生成一个递增的序号序列,从而实现按天数循环的目的。 - **`LAST_DAY()`与`...

    Oracle查询优化改写 技巧与案例

    本篇将围绕Oracle查询优化改写的技巧与实际案例进行深入探讨。 一、了解执行计划 在Oracle中,查询优化是通过执行计划来实现的。理解执行计划可以帮助我们分析SQL语句的运行过程,识别潜在的性能瓶颈。执行计划由...

    oracle查询优化

    Oracle SQL 查询优化是提高数据库性能的...通过这些优化技巧,可以显著提升Oracle SQL查询的效率,降低系统资源消耗,提高整体数据库性能。在实际应用中,需要结合具体业务场景和查询模式进行调整,以达到最佳效果。

    Oracle层次查询和with函数的使用示例

    Oracle数据库在处理层次数据时,提供了强大的查询能力,其中就包括层次查询(Hierarchical Query)和WITH函数。这两种方法在处理具有层级结构的数据,如组织结构、产品分类、树状菜单等场景时尤为有用。 首先,我们...

    递归查询菜单树,支持mysql,oracle

    在IT行业中,数据库管理和数据操作是...总的来说,递归查询菜单树是数据库操作的一个常见应用场景,它涉及到数据库设计、SQL查询技巧以及前后端的数据交换。理解并掌握这些知识点对于开发高效、可维护的系统至关重要。

    oracle查询成树状

    在Oracle数据库中,将查询结果转化为树状结构是一项高级而实用的技能,尤其适用于处理具有层级关系的数据,如产品分类、组织架构等。本篇将深入解析如何利用Oracle的特定功能,实现数据的树状展示。 ### 核心概念:...

    Oracle中的树状查询(递归查询)

    - CSDN社区(如`Oracle中的树状查询(递归查询) - 鱼与飞鸟 - CSDNBlog.files`所指)和其他在线论坛有许多实用的技巧和经验分享。 通过理解和掌握Oracle中的递归查询,我们可以有效地处理层次数据,构建和查询复杂...

    oracle树查询

    ### Oracle树查询详解 ...以上是关于Oracle树查询的一些基本用法和进阶技巧。这些查询方法可以帮助我们在处理具有层次结构的数据时更加灵活高效。希望本文能够帮助大家更好地理解和掌握Oracle中的树查询技术。

    剑破冰山++Oracle开发艺术[1].part10

    本书主要覆盖Oracle开发必备的重要知识点:数据库编程规范、Oracle开发常用工具及使用、MERGE方法、神秘的NULL和讨厌的CHAR、扩展GROUP BY、Oracle自动类型转换、Oracle分析函数、Oracle层次查询、11g R2新特性之...

    oracle-----oracle多表查询

    本篇将深入探讨Oracle中的多表查询技术,包括基本概念、联接类型、子查询以及高级查询技巧。 一、基本概念 1. 表关系:在数据库设计中,表与表之间可能存在一对一、一对多、多对多的关系。这些关系决定了我们需要...

    嵌套查询总结例子

    嵌套查询在Oracle分页查询中扮演着关键角色,不仅能解决ROWNUM与ORDER BY的冲突问题,还能通过合理的层次设计优化查询性能。通过理解并熟练掌握三层嵌套查询的技巧,数据库管理员和开发人员能够更高效地管理大量数据...

    oracle查询语句大全

    本文将详细介绍Oracle中常用的查询语句,包括条件查询、模糊查询、多层次查询以及内外连接查询等。 #### 二、基本查询语句 1. **查询所有列**: ```sql SELECT * FROM emp; ``` 这条语句用于获取`emp`表中的...

    Oracle经典教程1——走进Oracle

    高级查询涵盖了更复杂的SQL技巧,如子查询、联接操作、聚合函数等。这些技术有助于从数据库中获取更深入的信息。 #### 本章总结 本章重点介绍了SQL语言的基本概念和Oracle数据库中的数据操作方法。通过学习本章...

    在ORACLE、MSSQL、MYSQL中树结构表递归查询的实现.pdf

    MYSQL在早期版本中并不直接支持递归查询,但是可以通过一些技巧来模拟递归查询。例如,可以使用两个嵌套的SELECT语句,其中外层的SELECT语句与内层的SELECT语句通过NOT EXISTS子句进行连接。内层查询用于获取“子”...

Global site tag (gtag.js) - Google Analytics