`
yuxuguang
  • 浏览: 139142 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

sys_connect_by_path纵转横

阅读更多

个人觉得这个函数其实很好用,sys_connect_by_path(字段名, 2个字段之间的连接符号),注意这里的连接符号不要使用逗号,oracle会报错,如果一定要用,可以使用replace替换一下,方法如下 REPLACE(字段名,原字符,',')。
还有,这个函数使用之前必须先建立一个树,否则无用。
举个例子:
目的:将num值相等的项目写成 seq1,seq2,seq3,……的形式
(SELECT num,REPLACE(MAX(sql0), ';', ',')
                          FROM (SELECT num, sys_connect_by_path(sql1, ';') AS sql0
                                  FROM (SELECT num, sql1, rn, lead(rn) over(PARTITION BY num ORDER BY rn) rn1
                                          FROM (SELECT num, sql1, row_number() over(ORDER BY num, sql1 DESC) rn FROM tlsbk))
                                 START WITH num = '1' AND rn1 IS NULL
                                CONNECT BY rn1 = PRIOR rn));
结果:
num REPLACE(MAX(sql0), ';', ',')
--------------------------------------------------------
1 sql0,sql1,sql2
2 sql20,sql21,sql23,sql24,sql25
3 sql30,sql31,sql32,sql33,sql34,sql35,sql36

树结构和它的专用函数SYS_CONNECT_BY_PATH(网摘:http://blog.oracle.com.cn/html/83/t-122083.html)
简单的树型结构
关于树的普通应用
学习了下这个函数, 用ORGINDUSTRIES的表做了个测试:
正常的树型结构
select lpad(' ',6*(level-1))||industry,indlevel,indid,pindid
from ORGINDUSTRIES
start with indid=1
connect by pindid=prior indid
结果显示如下
                 Indlevel  indid    pindid
        服装与服饰               1             1             0
              服装               2             2               1
                    女装        3             3               2

倒型树
下面这个例子是个”倒数”—倒过来的树型结构
select lpad(' ',6*(level-1))||industry,indlevel,indid,pindid
from ORGINDUSTRIES
start with indid=20
connect by indid=prior pindid;
这是标准结果:
                             Indlevel indid    pindid
二手服装                      3        20       2
      服装                    2        2        1
            服装与服饰        1        1        0
结论
无论正树还是倒树, 关键就在于connect by的条件.
正树:  必须是  ‘父’= prior ‘子’
倒树:  必须是  ‘子’= prior ‘父’

树型结构的条件过滤
采用树型结构的话, 如果我们想将树上的一个分支砍掉.  将分支后面的结构都抛弃掉, 这个可以实现麽?当然可以。 但是不是用where, where条件只能去除单一的条件。
所以, 这种树型的过滤条件就需要加在connect by上面。

测试如下:由于用真实环境比较贴近实际,所以提前用下SYS_CONNECT_BY_PATH函数来显示下环境

不加任何条件的环境:
select areaname,sys_connect_by_path(areaname,',')
from areas bb
start with areaname='中国大陆'
connect by parentareaid=prior areaid  

结果:
1        中国大陆,中国大陆
2        北京        ,中国大陆,北京
3        北京        ,中国大陆,北京,北京
4        东城区        ,中国大陆,北京,东城区
5        西城区        ,中国大陆,北京,西城区
22        广东        ,中国大陆,广东
23        广州        ,中国大陆,广东,广州
24        汕尾        ,中国大陆,广东,汕尾
25        潮阳        ,中国大陆,广东,潮阳
46        上海        ,中国大陆,上海
47        上海        ,中国大陆,上海,上海
48        黄浦区        ,中国大陆,上海,黄浦区
49        闸北区        ,中国大陆,上海,闸北区


加了where过滤条件的SQL:
select areaname,sys_connect_by_path(areaname,',')
from areas bb
where bb.areaid>861000
start with areaname='中国大陆'
connect by parentareaid=prior areaid

结果为:
2        北京        ,中国大陆,北京
3        北京        ,中国大陆,北京,北京
4        东城区        ,中国大陆,北京,东城区
5        西城区        ,中国大陆,北京,西城区
22        广东        ,中国大陆,广东
23        广州        ,中国大陆,广东,广州
24        汕尾        ,中国大陆,广东,汕尾
25        潮阳        ,中国大陆,广东,潮阳
46        上海        ,中国大陆,上海
47        上海        ,中国大陆,上海,上海
48        黄浦区        ,中国大陆,上海,黄浦区
49        闸北区        ,中国大陆,上海,闸北区

结论:去掉了“1        中国大陆,中国大陆”数据

加了connect by的过滤条件:
select areaname,sys_connect_by_path(areaname,',')
from areas bb
where bb.areaid>861000
start with areaname='中国大陆'
connect by parentareaid=prior areaid  and areaname<>'广东'

结果为:
2        北京        ,中国大陆,北京
3        北京        ,中国大陆,北京,北京
4        东城区        ,中国大陆,北京,东城区
5        西城区        ,中国大陆,北京,西城区
46        上海        ,中国大陆,上海
47        上海        ,中国大陆,上海,上海
48        黄浦区        ,中国大陆,上海,黄浦区
49        闸北区        ,中国大陆,上海,闸北区

结论:去掉了整个广东的分支,  在结果集中只有北京和上海


SYS_CONNECT_BY_PATH函数
采用SYS_CONNECT_BY_PATH函数为:

select industry,sys_connect_by_path(industry,'/')
from ORGINDUSTRIES
start with indid=3
connect by indid=prior pindid;

结果为:
女装               /女装
服装               /女装/服装
服装与服饰            /女装/服装/服装与服饰

这样的话, 就可以实现, 树结构的结果集的单行拼接:

我们只需要取最大的字段就OK了

测试如下:

select max(sys_connect_by_path(industry,'/'))
from ORGINDUSTRIES
start with indid=3
connect by indid=prior pindid;

结果为:
/女装/服装/服装与服饰


复杂的树型结构――多列变单列
树型结构也分单树和多树(我的称呼,实际上就是指单支和多支)
对于下面的这种情况, 我们必须要构造的树就属于单支树。
原始环境
环境如下:
select * from test;

结果为:
1        n1
1        n2
1        n3
1        n4
1        n5
3        t1
3        t2
3        t3
3        t4
3        t5
3        t6
2        m1

造树
脚本如下:
select no,q,
       no+row_number() over( order by no) rn,
       row_number() over(partition by no order by no) rn1
from test

结果如下:
No  Q  RN RN1
1        n1        2        1
1        n2        3        2
1        n3        4        3
1        n4        5        4
1        n5        6        5
2        m1        8        1
3        t1        10        1
3        t2        11        2
3        t3        12        3
3        t4        13        4
3        t5        14        5
3        t6        15        6

每列的目的是:
RN1列主要的目的是分组, 按照value值‘1’,我们可以start with使用它。

RN列主要用来做connect by使用。 实际上它就是我们要的树。
第一个支: 2,3,4,5,6
第二个支: 8
第三个支: 10,11,12,13,14,15

中间为什么要断掉:7,9  目的就是为了区别每个分支。 到后面看具体的SQL,就明白这里的说法了。

杀手锏
既然我们有了树, 就可以使用树型函数SYS_CONNECT_BY_PATH和connect by啦,来拼接我们所需要的多列值。

脚本如下:
select no,sys_connect_by_path(q,',')
from (
select no,q,
       no+row_number() over( order by no) rn,
       row_number() over(partition by no order by no) rn1
from test
)
start with rn1=1
connect by rn-1=prior rn

结果为:
1        ,n1
1        ,n1,n2
1        ,n1,n2,n3
1        ,n1,n2,n3,n4
1        ,n1,n2,n3,n4,n5
2        ,m1
3        ,t1
3        ,t1,t2
3        ,t1,t2,t3
3        ,t1,t2,t3,t4
3        ,t1,t2,t3,t4,t5
3        ,t1,t2,t3,t4,t5,t6

终极武器
最终我们要的值,是单列值, 其实想想, 也就是最长的一行咯。 那么就好办了。 我们直接GROUP BY ,然后取MAX值。
脚本如下:
select no,max(sys_connect_by_path(q,','))
from (
select no,q,
       no+row_number() over( order by no) rn,
       row_number() over(partition by no order by no) rn1
from test
)
start with rn1=1
connect by rn-1=prior rn
group by no

结果为:
1        ,n1,n2,n3,n4,n5
2        ,m1
3        ,t1,t2,t3,t4,t5,t6

如果觉得前面的‘,’不好看,可以使用ltrim去掉。 或者用substr也可以。
如下:
ltrim(max(sys_connect_by_path(q,',')),',')
或者
substr(max(sys_connect_by_path(q,',')),2)

分享到:
评论
1 楼 Eric.Yan 2012-05-29  
学习了……

相关推荐

    sys_connect_by_path的用法20220526.txt

    行列转换,层级关系,oracle sys_connect_by_path的用法

    connect_by_path和connect_by_root比较总结

    通过实例比较了 SYS_CONNECT_BY_PATH 和 CONNECT_BY_ROOT 的异同,和返回树形的数据结构

    oracle sys_connect_by_path 函数 结果集连接

    Oracle的`sys_connect_by_path`函数是一个非常有用的工具,尤其在构建树状结构的数据时。在本文中,我们将深入理解这个函数以及如何将其应用于非树结构的数据以生成所需的结果。 `sys_connect_by_path`函数的基本...

    ORACLE查询树型关系(connect_by_prior_start_with)

    使用 START WITH 和 CONNECT BY 子句可以实现 SQL 的层次查询,并且可以使用 SYS_CONNECT_BY_PATH 函数和 CONNECT_BY_ROOT、CONNECT_BY_ISLEAF、CONNECT_BY_ISCYCLE 等伪列函数来增强层次查询的能力。

    oracle connect by level 应用

    `CONNECT BY`还可以结合`SYS_CONNECT_BY_PATH`函数,用于返回从起始节点到当前节点的路径。例如,我们可以添加一个路径列来显示每个员工的晋升路径: ```sql SELECT EMPLOYEE_NAME, MANAGER_NAME, SYS_...

    oracle列合并的实现方法

    很多场合我们都会用到...sys_connect_by_path(字段名, 2个字段之间的连接符号),这里的连接符号不要使用逗号,oracle会报错,如果一定要用,可以使用replace替换一下,方法如下 REPLACE(字段名,原字符,’,’)。这个

    MySQL实现类似于connect_by_isleaf的功能MySQL方法或存储过程

    在MySQL中,面对类似Oracle的`connect_by_isleaf`功能的需求,即查找并修改指定ID的所有子级记录,可以通过自连接、存储过程或者递归函数等方法实现。这里我们主要探讨两种MySQL的实现方式:一种是使用用户定义的...

    Oracle的Connect By使用示例

    SELECT LTRIM(SYS_CONNECT_BY_PATH(ID, '-'), '-') AS PATH, ID, NAME, LEVEL FROM TBL_TEST START WITH id = 1 CONNECT BY PRIOR id = pid; ``` - **解释**:利用`SYS_CONNECT_BY_PATH`函数构建出每条记录的...

    【Oracle】树状结构查询

    SELECT LEVEL, CONNECT_BY_ISCYCLE, CONNECT_BY_ISLEAF, SYS_CONNECT_BY_PATH(a.ename, '/'), a.* FROM empa WHERE a.empno &lt;&gt; 7369 START WITH a.empno = 7839 CONNECT BY NOCYCLE PRIOR a.empno = a.mgr; ``` ...

    sql实现多行合并一行

    在Oracle中,我们可以利用`CONNECT BY`和`SYS_CONNECT_BY_PATH`函数来实现这个目标。`CONNECT BY`用于建立树形连接,而`SYS_CONNECT_BY_PATH`则可以沿着这些连接路径收集数据。 以下是一个详细的步骤解释: 1. ...

    如何取得一个表的所有字段名用逗号分割

    SYS_CONNECT_BY_PATH 函数是 Oracle 9i 及其后续版本中提供的一个系统函数,它可以将从父节点到当前行内容以“path”或者层次元素列表的形式显示出来。这个函数的基本语法是: ```sql SYS_CONNECT_BY_PATH( string, ...

    oracle-tree-sql.rar_oracle

    理解并熟练掌握`CONNECT BY`、`PRIOR`、`sys_connect_by_path`等关键字和函数,可以帮助我们更高效地处理树形结构的数据。在实际应用中,还需要考虑性能优化,如合理设计表结构和使用索引,以确保查询的效率。

    多行合并为一行的SQL语句.docx

    这个例子展示了如何使用SQL层级查询功能(如`CONNECT BY`和`SYS_CONNECT_BY_PATH`)来合并具有相同编号的多行数据为一行。这种方式适用于那些希望将分散的数据整合成紧凑格式的需求场景。此外,通过调整`SYS_CONNECT...

    oracle多行合并一行

    2. **使用`SYS_CONNECT_BY_PATH`函数**:该函数可以递归地遍历每一组中的所有记录,并生成一个由逗号连接的字符串。 3. **使用`ROW_NUMBER()`与`PARTITION BY`结合**:再次使用`ROW_NUMBER()`函数,并结合`PARTITION...

    oracle-sql

    总的来说,Oracle SQL提供了丰富的层次查询和数据清理工具,如SYS_CONNECT_BY_PATH、CONNECT_BY_ISLEAF、CONNECT_BY_ROOT和CONNECT_BY_ISCYCLE等,使得在处理层次结构数据和大量数据清理时更为便捷高效。同时,理解...

    Oracle中分组后拼接分组字符串.pdf

    最后,我们使用 `sys_connect_by_path()` 函数来拼接分组后的数据,并使用 `start with` 子句和 `connect by` 子句来实现递归操作: ```sql select No, ltrim(max(sys_connect_by_path(Value, ';')), ';') as ...

    oracle多行转为字符串总结

    介绍了将多行转为字符串的三种方案,并比较了三种方案的执行效率. 1.sys_connect_by_path + start with ... connect by ... prior + 分析函数 2.自定义Function/SP 3.使用 Oracle 10g 内置函数 wmsys.wm_concat

Global site tag (gtag.js) - Google Analytics