sys_connect_by_path 进行列连接

本文介绍了如何使用SQL中的sys_connect_by_path函数进行列连接,通过示例展示了如何创建表、插入数据,并通过该函数将相同分组的列值按顺序连接,以实现数据的聚合展示。
1 、创建表并插入数据
SQL
>   create   table  test(a  number ,b  varchar2 ( 20 ));
SQL
>   select   *   from  test;

         A B
-- -------- --------------------
          1  a
         
1  b
         
1  c
         
1  d
         
1  e
         
2  a
         
2  b
         
3  a
         
3  v
         
3  d

10  rows selected
查看合并列结果
select  a, max (sys_connect_by_path(b, ' ; ' )) result
from
(
select  a,b,
        (row_number() 
over ( order   by  a,b  desc
        
-- row_number()-1 over(order by a,b desc) rn1
         + dense_rank()  over ( order   by  a)) rn,
        
max (b)  over (partition  by  a) bs
 
from  test)
 start 
with  b = bs 
 connect 
by  rn - 1   =  prior rn
 
group   by  a;

结果如下:
         A RESULT
-- -------- --------------------------------------------------------------------------------
          1  ;e;d;c;b;a
         
2  ;b;a
         
3  ;v;d;a
 
或者
select  a, max (sys_connect_by_path(b, ' ; ' )) result
from
(
select  a,b,
        row_number() 
over ( order   by  a,b  desc ) rn,
        row_number() 
over ( order   by  a,b  desc ) - 1  rn1,
        
-- +dense_rank() over(order by a)) rn,
         max (b)  over (partition  by  a) bs
 
from  test)
 start 
with  b = bs 
 connect 
by  rn1  =  prior rn  and  a  =  prior a
 
group   by  a;
注释:
select  a,b,rn,lead(rn)  over (partition  by  a  order   by  rn) rn1
 
from
(
select  a,b,row_number()  over ( order   by  a,b  desc ) rn  from  test)
结果如下:
         A B                            RN        RN1
-- -------- -------------------- ---------- ----------
          1  e                              1            2
         
1  d                              2            3
         
1  c                              3            4
         
1  b                              4            5
         
1  a                              5  
         
2  b                              6            7
         
2  a                              7  
         
3  v                              8            9
         
3  d                              9           10
         
3  a                             10  

10  rows selected

select  a ,sys_connect_by_path(b, ' ; ' ) result  from
(
select  a,b,rn,lead(rn)  over (partition  by  a  order   by  rn) rn1
 
from
(
select  a,b,row_number()  over ( order   by  a,b  desc ) rn  from  test))
start 
with  a = 1   and  rn1  is   null  connect  by  rn1 = prior rn;
结果如下:
         A RESULT
-- -------- --------------------------------------------------------------------------------
          1  ;a
         
1  ;a;b
         
1  ;a;b;c
         
1  ;a;b;c;d
         
1  ;a;b;c;d;e
体会另见 http://www.itpub.net/823705.html
<think> 我们正在讨论的是Oracle中的SYS_CONNECT_BY_PATH函数,它在层次查询(CONNECT BY)中使用,用于形成从根节点到当前节点的路径字符串。 用户的问题是在联合查询(UNION)中使用SYS_CONNECT_BY_PATH,这实际上是一个特定的场景,因为通常SYS_CONNECT_BY_PATH是在单个层次查询中使用。 但我们可以考虑这样的场景:将多个层次查询的结果合并在一起,每个层次查询使用SYS_CONNECT_BY_PATH生成路径。 注意:在联合查询中,每个SELECT语句都可以是一个独立的层次查询,然后在最外层使用UNION或UNION ALL合并。 例如,假设我们有两个表(或同一个表的不同部分)需要进行层次查询,并生成路径,然后将结果合并。 步骤: 1. 分别写出两个层次查询,每个查询中都可以使用SYS_CONNECT_BY_PATH。 2. 确保两个查询的数和数据类型兼容(因为UNION的要求)。 3. 使用UNION或UNION ALL合并。 注意:在Oracle中,每个层次查询必须包含START WITH和CONNECT BY子句。 示例: 假设我们有两个表:table1和table2,它们具有相同的结构(id, parent_id, name)。我们想要分别对这两个表进行层次查询,并合并结果。 查询1:对table1进行层次查询,生成路径(以'/'分隔) 查询2:对table2进行层次查询,生成路径(同样以'/'分隔) 然后使用UNION ALL合并。 具体SQL如下: ```sql -- 查询table1的层次结构 SELECT id, name, SYS_CONNECT_BY_PATH(name, '/') AS path FROM table1 START WITH parent_id IS NULL -- 假设根节点的parent_id为空 CONNECT BY PRIOR id = parent_id UNION ALL -- 查询table2的层次结构 SELECT id, name, SYS_CONNECT_BY_PATH(name, '/') AS path FROM table2 START WITH parent_id IS NULL CONNECT BY PRIOR id = parent_id; ``` 注意:如果两个表的不完全一致(比如名不同),我们需要在SELECT表中调整,使其对应。 另外,如果我们需要在联合查询的结果上进行排序等操作,可以将整个联合查询作为子查询,然后在外层进行排序。 例如,按照路径的长度排序: ```sql SELECT * FROM ( SELECT id, name, SYS_CONNECT_BY_PATH(name, '/') AS path, LENGTH(SYS_CONNECT_BY_PATH(name, '/')) AS path_length FROM table1 START WITH parent_id IS NULL CONNECT BY PRIOR id = parent_id UNION ALL SELECT id, name, SYS_CONNECT_BY_PATH(name, '/') AS path, LENGTH(SYS_CONNECT_BY_PATH(name, '/')) AS path_length FROM table2 START WITH parent_id IS NULL CONNECT BY PRIOR id = parent_id ) ORDER BY path_length; ``` 注意事项: 1. SYS_CONNECT_BY_PATH函数仅在层次查询中有效,所以每个部分都必须有CONNECT BY子句。 2. 在联合查询中,每个SELECT语句中的SYS_CONNECT_BY_PATH都会独立作用于其自身的层次结构。 3. 由于层次查询可能返回多行,联合查询的结果将是两个层次结构结果的简单合并。 另外,引用[4]中提到在MySQL中实现类似功能,但用户的问题是关于Oracle的,所以我们主要关注Oracle的使用。 如果用户需要将这样的查询转换到MySQL,可以使用递归CTE(MySQL 8.0+)和字符串连接的方式模拟,但这不是当前问题关注的。 因此,联合查询中使用SYS_CONNECT_BY_PATH的方法就是分别在每个SELECT子句(每个层次查询)中使用,然后合并。 下面我们给出一个更具体的示例,使用引用[3]中的表结构(ORGPOST_TREE表)进行联合查询: 假设我们有两个部门结构表:ORGPOST_TREE_A和ORGPOST_TREE_B,它们的结构相同(IDS, P_ID, REF_ID)。我们想要合并两个表的层次路径。 ```sql SELECT T.IDS, T.REF_ID, SYS_CONNECT_BY_PATH(T.REF_ID, '->') AS "PATH" FROM ORGPOST_TREE_A T START WITH T.P_ID = '0' CONNECT BY PRIOR T.IDS = T.P_ID UNION ALL SELECT T.IDS, T.REF_ID, SYS_CONNECT_BY_PATH(T.REF_ID, '->') AS "PATH" FROM ORGPOST_TREE_B T START WITH T.P_ID = '0' CONNECT BY PRIOR T.IDS = T.P_ID; ``` 这样我们就得到了两个表的合并层次路径结果。 注意事项: 1. 确保每个层次查询的起始条件(START WITH)和连接条件(CONNECT BY)正确。 2. 注意两个表的层次结构可能独立,所以生成的路径也是独立的。 3. 使用UNION ALL不会去重,如果两个表中有相同的节点ID,但路径不同,都会保留。如果要去重,使用UNION,但注意UNION会基于所有去重,这可能不是我们想要的(因为路径可能不同)。 4. 性能:层次查询通常涉及递归,数据量大时可能会有性能问题,特别是在联合查询中两个表都很大时。可以考虑在父ID上建立索引。 最后,生成相关问题。 </think> ### 联合查询中使用 SYS_CONNECT_BY_PATH 的方法及示例 #### 一、核心概念解析 **SYS_CONNECT_BY_PATH** 是 Oracle 特有的层次查询函数,用于生成从根节点到当前节点的路径字符串: 1. **语法结构**:`SYS_CONNECT_BY_PATH(column, delimiter)` 2. **依赖条件**:必须与 `START WITH...CONNECT BY PRIOR` 层次查询语句配合使用[^1][^3] 3. **典型场景**:组织机构树、分类层级、文件路径等递归结构的数据展示 #### 二、联合查询中的使用方法 在联合查询中整合层次查询结果时,需注意: ```sql -- 基础结构 (SELECT 层次查询结果 FROM 表A) UNION ALL (SELECT 层次查询结果 FROM 表B) ``` **关键要点**: 1. 每个子查询必须包含完整的 `START WITH...CONNECT BY PRIOR` 语句 2. 路径分隔符需保持一致(如 `/` 或 `->`) 3. 联合查询的数量和类型必须兼容 #### 三、完整示例 ##### 场景:合并两个部门的组织架构树 ```sql -- 部门A的层级 SELECT employee_id, SYS_CONNECT_BY_PATH(employee_name, '->') AS org_path, LEVEL FROM dept_a START WITH manager_id IS NULL -- 从根节点开始 CONNECT BY PRIOR employee_id = manager_id UNION ALL -- 部门B的层级 SELECT employee_id, SYS_CONNECT_BY_PATH(employee_name, '->') AS org_path, LEVEL FROM dept_b START WITH manager_id = 0 -- 根节点条件不同[^4] CONNECT BY PRIOR employee_id = manager_id ORDER BY LEVEL, org_path; ``` ##### 示例输出: | EMPLOYEE_ID | ORG_PATH | LEVEL | |-------------|-------------------------|-------| | 1001 | ->CEO | 1 | | 2001 | ->CTO | 1 | | 1002 | ->CEO->Finance_Mgr | 2 | | 2002 | ->CTO->Dev_Lead | 2 | #### 四、进阶用法:路径解析 结合正则表达式拆分路径层次[^4]: ```sql SELECT org_path, REGEXP_SUBSTR(org_path, '[^/]+', 1, 1) AS level1, REGEXP_SUBSTR(org_path, '[^/]+', 1, 2) AS level2 FROM ( SELECT SYS_CONNECT_BY_PATH(dept_name, '/') AS org_path FROM department START WITH parent_dept_id IS NULL CONNECT BY PRIOR dept_id = parent_dept_id UNION ALL SELECT SYS_CONNECT_BY_PATH(dept_name, '/') FROM sub_organization START WITH parent_dept_id = 0 CONNECT BY PRIOR dept_id = parent_dept_id ); ``` #### 五、注意事项 1. **版本兼容性** - 仅 Oracle 9i+ 支持(10g 增强循环检测功能[^5]) - MySQL/PostgreSQL 需使用递归 CTE 实现类似功能 2. **性能优化** ```sql -- 为连接创建索引 CREATE INDEX idx_manager ON dept_a(manager_id); CREATE INDEX idx_parent ON dept_b(manager_id); ``` 3. **常见错误** - `ORA-01489`: 路径字符串超过 4000 字节(需用 `SUBSTR` 截断) - `ORA-00600`: 递归层次过深(超过 Oracle 默认的 255 层限制) > 迁移提示:Oracle 到 MySQL 的转换需改用递归 CTE 和字符串拼接[^2] > ```sql > WITH RECURSIVE cte AS ( > SELECT id, name, CAST(name AS CHAR(1000)) AS path > FROM emp WHERE manager_id IS NULL > UNION ALL > SELECT e.id, e.name, CONCAT(cte.path, '->', e.name) > FROM emp e JOIN cte ON e.manager_id = cte.id > ) > SELECT * FROM cte; > ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值