oracle层级关系按列存储_[转载]Oracle层次查询及应用(start with connect by)

摘要:本文将根据对层次查询语句简单例子的说明来理解应用,并举例实际的应用案例。

========================================================================================================

start with connect by 层次查询(Hierarchical Queries)

========================================================================================================

语法:

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

SELECT *

FROM table

WHERE

START WITH

CONNECT BY

ORDER BY col1, col2 ...

SELECT *

FROM table

START WITH ID = 1

CONNECT BY PRIOR PID = ID

start with: 表示根记录的条件

connect by: 指定了父记录行和子记录行之间的关系,在层次查询中,条件表达式必须使用prior操作符来指定父记录行

如:

CONNECT BY PRIOR pid = id 或者CONNECT BY pid = PRIOR id

如果connect by 条件是一个组合条件,那么只有一个条件需要prior操作符,

如:

CONNECT BY last_name != 'King' AND PRIOR employee_id =

manager_id

不过,connect by 不能包含子查询。

prior是一个二元操作符,最常见的是用于列值相等的比较,它让Oracle使用对应列的父亲行的值。使用非相等比较,极有可能倒致查询陷入无穷循环,以出错终止。

举例:

========================================================================================================

Start with...Connect

By子句递归查询一般用于一个表维护树形结构的应用。可以通过一个简单的例子来理解其使用的概念和方法。

创建示例表:

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

CREATE TABLE tbl_test

(

ID NUMBER,

NAME VARCHAR2(10),

pid NUMBER

DEFAULT 0

);

插入测试数据:

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

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('1','111','0');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('2','222','1');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('3','333','0');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('4','444','1');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('5','555','2');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('6','666','0');

INSERT INTO TBL_TEST(ID,NAME,PID) VALUES('9','999','2');

全部记录

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

SELECT * FROM tbl_test

如下记录

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

ID NAME PID

1 111 0 2 222 1 3 333 0 4 444 1 5 555 2 6 666 0 9 999 2

从父记录行向子记录行递归

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

SELECT *

FROM tbl_test

START WITH ID = 1

CONNECT BY PRIOR ID = pid

如下记录

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

ID NAME PID

1 111 0 2 222 1 5 555 2 9 999 2 4 444 1 --------------------

解析:

1.(START WITH ID = 1)根记录条件为ID=1

2.(CONNECT BY PRIOR ID =

pid):由列ID与PID建立父子关系并进行比较,从ID为1开始,在PID列中寻找为1的行,可以找到ID为2和4,再将ID为2和4从PID中再寻找,又可以找到5和9,以上结果因此而来。

从子记录向父记录递归

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

SELECT *

FROM tbl_test

START WITH ID = 5

CONNECT BY PRIOR pid = ID

如下记录

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

ID NAME PID

5 555 2 2 222 1 1 111 0 --------------------

解析:

1.(START WITH ID = 5)根记录条件为ID=5

2.(CONNECT BY PRIOR pid =

ID):以之上查询恰相反,其中的取值也正相反。ID为5的PID列的值为2,因PRIOR在PID列一边,确从PID列中取值,在PID列取值2向ID

列进行递归查询,在ID列中找到2的值,再确认其对应的PID为1,再次取值1在ID中找到结果,最终共计三条记录。

========================================================================================================

LEVEL,ROW_NUMBER,OVER的应用

========================================================================================================

设PID为父值,并根据PID进行分组及确定LEVEL

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

SELECT LEVEL, pid,

ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid) by_pid,

ROW_NUMBER () OVER (ORDER BY pid) AS rn, NAME

FROM tbl_test

START WITH pid = 0

CONNECT BY PRIOR ID = pid

ORDER BY 1

如下记录

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

LEVEL PID BY_PID RN NAME

1 0 1 1 111 1 0 2 2 333 1 0 3 3 666 2 1 1 4 222 2 1 2 5 444 3 2 1 6 555 3 2 2 7 999 根据父值逐层区分

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

SELECT pid, ID,

(CASE

WHEN LEVEL = 1

THEN NAME

WHEN LEVEL = 2

THEN

' ' || NAME

WHEN LEVEL = 3

THEN

' ' || NAME

END

) bs_name

FROM tbl_test

START WITH pid = 0

CONNECT BY pid = PRIOR ID

记录如下:

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

PID ID BS_NAME

0 1 111 1 2 222 2 5 555 2 9 999 1 4 444 0 3 333 0 6 666

可以清楚看出,ID为1,其子值为2和4(level 2),而2值又有子值5、9(level 3),3、6无子值存在。

========================================================================================================

SYS_CONNECT_BY_PATH 函数

========================================================================================================

以上例显示看出,PID分为三个分支,NAME分别如下:

第一分支:111,333,666

第二分支:222,444

第三分支:555,999

脚本:

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

SELECT pid, SYS_CONNECT_BY_PATH (by_path, ',')

FROM (SELECT pid,

ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid)

by_pid,

ROW_NUMBER () OVER (ORDER BY pid) + pid AS rn,

NAME AS by_path

FROM tbl_test

ORDER BY 1)

START WITH by_pid = 1

CONNECT BY rn - 1 = PRIOR rn

ORDER BY 1

记录结果:

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

PID SYS_CONNECT_BY_PATH(BY_PATH,',')

0 ,111 0 ,111,333 0 ,111,333,666 1 ,222 1 ,222,444 2 ,555 2 ,555,999

如取单值列,可取其中最大值,使用MAX,然后应用GROUP BY即可,如下脚本:

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

SELECT pid, LTRIM (MAX (SYS_CONNECT_BY_PATH (by_path, ',')), ',')

FROM (SELECT pid,

ROW_NUMBER () OVER (PARTITION BY pid ORDER BY pid)

by_pid,

ROW_NUMBER () OVER (ORDER BY pid) + pid AS rn,

NAME AS by_path

FROM tbl_test

ORDER BY 1)

START WITH by_pid = 1

CONNECT BY rn - 1 = PRIOR rn

GROUP BY pid

ORDER BY 1

记录结果:

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

PID LTRIM(MAX(SYS_CONNECT_BY_PATH(BY_PATH,',')),',')

0 111,333,666 1 222,444 2 555,999 --------------------------------------------------------------------------------------------------------

常用于行列转换的应用。

应用:

一、ERP BOM(物料清单)

========================================================================================================

SELECT DISTINCT b.lvl lv, msi1.segment1 p_item, msi1.description

p_item_desc,

msi1.primary_uom_code, b.item_num num, b.operation_seq_num,

msi2.segment1 c_item, msi2.description c_item_desc,

msi2.primary_uom_code, b.component_quantity,

b.component_yield_factor,

DECODE (b.wip_supply_type,

1, 'Push',

2, 'Assembly Pull'

) TYPE, b.supply_subinventory, b.planning_factor

FROM inv.mtl_system_items_b msi1,

inv.mtl_system_items_b msi2,

bom.bom_structures_b bom,

inv.mtl_parameters mp,

(SELECT LEVEL lvl, bic.bill_sequence_id,

bic.component_item_id, bic.component_quantity,

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值