`
wang4674890
  • 浏览: 87866 次
  • 性别: Icon_minigender_2
  • 来自: 厦门
社区版块
存档分类
最新评论

利用Oracle分析函数实现多行数据合并为一行

 
阅读更多

demo场景,以oracle自带库中的表emp为例:
  select ename,deptno from emp order by deptno;

  

ENAME       DEPTNO
CLARK       10
KING         10
MILLER     10
SMITH       20
ADAMS      20
FORD        20
SCOTT      20
JONES      20
ALLEN      30
BLAKE      30
MARTIN    30
JAMES      30
TURNER   30
WARD      30

    现在想要将同一部门的人给合并成一行记录,如何做呢?如下:



  

ENAME                                  DEPTNO
CLARK,KING,MILLER                      10
ADAMS,FORD,JONES,SCOTT,SMITH           20
ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD   30

  通常我们都是自己写函数或在程序中处理,这里我们利用oracle自带的分析函数row_number()和sys_connect_by_path来进行sql语句层面的多行到单行的合并,并且效率会非常高。

  基本思路:

  1、对deptno进行row_number()按ename排位并打上排位号

  select deptno,ename,row_number() over(partition by deptno order by deptno,ename) rank

  from emp order by deptno,ename;

DEPTNO ENAME     RANK
10     CLARK           1
10     KING              2
10     MILLER          3
20     ADAMS           1
20     FORD             2
20     JONES           3
20     SCOTT           4
20     SMITH           5
30     ALLEN           1
30     BLAKE           2
30     JAMES           3
30     MARTIN         4
30     TURNER        5
30     WARD           6

  可看出,经过row_number()后,部门人已经按部门和人名进行了排序,并打上了一个位置字段rank
2、利用oracle的递归查询connect by进行表内递归,并通过sys_connect_by_path进行父子数据追溯串的构造,这里要针对ename字段进行构造,使之合并在一个字段内(数据很多,只截取部分)

  select deptno,ename,rank,level as curr_level,

  ltrim(sys_connect_by_path(ename,','),',') ename_path from (

  select deptno,ename,row_number() over(partition by deptno order by deptno,ename) rank

  from emp order by deptno,ename) connect by deptno = prior deptno and rank-1 = prior rank;

  各部门递归后的数据量都是:(1+n)/2 * n 即:deptno=10 数据量:(1+3)/2 * 3 = 6;

  deptno=20 数据量:(1+5)/2 * 5 = 15;      deptno=30 数据量:(1+6)/2 * 6 = 21;

DEPTNO ENAME    RANK    CURR_LEVEL   ENAME_PATH
10     CLARK            1         1                    CLARK
10     KING              2          2                   CLARK,KING
10     MILLER          3          3                    CLARK,KING,MILLER
10     KING              2          1                     KING
10     MILLER          3          2                     KING,MILLER
10     MILLER          3         1                      MILLER



DEPTNO   ENAME   RANK    CURR_LEVEL       ENAME_PATH
20       ADAMS          1             1                      ADAMS
20       FORD            2             2                      ADAMS,FORD
20       JONES           3             3                      ADAMS,FORD,JONES
20       SCOTT           4             4                       ADAMS,FORD,JONES,SCOTT
20       SMITH           5              5                      ADAMS,FORD,JONES,SCOTT,SMITH
20       FORD            2              1                       FORD
20       JONES           3              2                      FORD,JONES
20       SCOTT           4              3                      FORD,JONES,SCOTT
20       SMITH           5              4                      FORD,JONES,SCOTT,SMITH
20       JONES           3              1                      JONES
20       SCOTT           4              2                      JONES,SCOTT
20       SMITH           5              3                       JONES,SCOTT,SMITH
20       SCOTT           4              1                      SCOTT
20       SMITH           5              2                       SCOTT,SMITH
20       SMITH           5               1                      SMITH

  这里我们仅列出deptno=10、20的,至此我们应该能否发现一些线索了,即每个部门中,curr_level最高的那行,有我们所需要的数据。那后面该怎么办,取出那个数据?对了,继续用row_number()进行排位标记,然后再按排位标记取出即可。

  3、 对deptno继续进行row_number()按curr_level排位

  select deptno,ename_path,row_number() over(partition by deptno order by deptno,curr_level desc) ename_path_rank from (select deptno,ename,rank,level as curr_level,

  ltrim(sys_connect_by_path(ename,','),',') ename_path from (

  select deptno,ename,row_number() over(partition by deptno order by deptno,ename) rank

  from emp order by deptno,ename) connect by deptno = prior deptno and rank-1 = prior rank);

DEPTNO ENAME_PATH              ENAME_PATH_RANK
10          CLARK,KING,MILLER    1
10          CLARK,KING                2
10          KING,MILLER              3
10          CLARK                        4
10          KING                          5
10          MILLER                       6


DEPTNO ENAME_PATH                                         ENAME_PATH_RANK
20          ADAMS,FORD,JONES,SCOTT,SMITH          1  
20          ADAMS,FORD,JONES,SCOTT                     2
20          FORD,JONES,SCOTT,SMITH                      3
20          ADAMS,FORD,JONES                                4
20          FORD,JONES,SCOTT                                 5
20          JONES,SCOTT,SMITH                               6
20          ADAMS,FORD                                           7
20          FORD,JONES                                            8
20          SCOTT,SMITH                                           9
20          JONES,SCOTT                                          10
20          ADAMS                                                     11
20          JONES                                                      12
20          SMITH                                                      13
20          SCOTT                                                     14
20          FORD                                                      15

  这里还是仅列出deptno为10、20的,至此应该很明了了,在进行一次查询,取ename_path_rank为1的即可获得我们想要的结果。
  4、获取想要排位的数据,即得部门下所有人多行到单行的合并

  select deptno,ename_path from (select deptno,ename_path,

  row_number() over(partition by deptno order by deptno,curr_level desc) ename_path_rank

  from (select deptno,ename,rank,level as curr_level,

  ltrim(sys_connect_by_path(ename,','),',') ename_path from (

  select deptno,ename,row_number() over(partition by deptno order by deptno,ename) rank

  from emp order by deptno,ename) connect by deptno = prior deptno and rank-1 = prior rank))

  where ename_path_rank=1;



代码
select deptno, ename_path
  from (select deptno,
               ename_path,
               row_number() over(partition by deptno order by deptno, curr_level desc) ename_path_rank
          from (
         
         
          select       empno,    
                       deptno,
                       ename,
                       rank,
                       level as curr_level,
                       ltrim(sys_connect_by_path(ename, ','), ',') ename_path
                  from (select deptno,
                               ename,
                               empno,
                               row_number() over(partition by deptno order by deptno, ename) rank
                          from emp
                         order by deptno, ename)
                connect by deptno = prior deptno
                       and rank - 1 = prior rank
               
                ))  where ename_path_rank = 1;

—————————————————————————————————————————————————
查询表中的一个字段,返回了多行,就把这么多行的数据都拼成一个字符串。

例:   id  name
       1   aa
       2   bb
       3   cc

  要的结果是"aa,bb,cc"

select WMSYS.WM_CONCAT(a.name) from user a

这样的话,查询出的结果:"aa.bb.cc"

中间用点间隔,如果想替换为其他符号,例如用逗分号

select replace(WMSYS.WM_CONCAT(a.name),',',';') from user a

结果:"aa;bb;cc"

 

分享到:
评论

相关推荐

    oracle实现多行合并的方法

    本文实例讲述了oracle实现多行合并的方法。分享给大家供大家参考。具体分析如下: 在写sql时,经常会有将某列的字段合并起来,比如将某人名下每个月的工资列示,但是每个人只能占一行。 像这种场景,可能用行列转换...

    Oracle行转列

    Oracle行转列是指在Oracle数据库中将行数据转换为列数据或将列数据转换为行数据的操作。这种操作在实际应用中非常有用,例如,在数据报表、数据分析和数据挖掘等领域都需要使用行转列操作。 1. 列转行 列转行是指...

    Oracle SQL高级编程(资深Oracle专家力作,OakTable团队推荐)--随书源代码

    作者通过总结各自多年的软件开发和教学培训经验,与大家分享了掌握Oracle SQL所独有的丰富功能的技巧所在,内容涵盖SQL执行、联结、集合、分析函数、子句、事务处理等多个方面。读者可以学习到以下几个方面的技巧:...

    OCPOCA认证考试指南全册:Oracle Database 11g(1Z0-051,1Z0-052,1Z0-053)--详细书签版(第2/2部分)

    他创办了自己的咨询公司,作为一名独立的顾问,他围绕大量的Oracle技术设计并开发了软件和培训课程,内容涉及数据库、应用服务器和商业智能产品,拥有12年的IT从业经验。  Bob Bryla是Oracle 9i和10g的认证专家,他...

    OCPOCA认证考试指南全册:Oracle Database 11g(1Z0-051,1Z0-052,1Z0-053)--详细书签版(第1/2部分)

    他创办了自己的咨询公司,作为一名独立的顾问,他围绕大量的Oracle技术设计并开发了软件和培训课程,内容涉及数据库、应用服务器和商业智能产品,拥有12年的IT从业经验。  Bob Bryla是Oracle 9i和10g的认证专家,他...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part1

    实例156 限制多行文本域输入的字符个数 187 实例157 设置文本框的只读属性 188 实例158 自动计算金额 189 实例159 为文本框设置默认值 190 实例160 设置文本框的样式 191 实例161 文本域的滚动条 192 3.3 下拉列表的...

    PHP开发实战1200例(第1卷).(清华出版.潘凯华.刘中华).part2

    实例156 限制多行文本域输入的字符个数 187 实例157 设置文本框的只读属性 188 实例158 自动计算金额 189 实例159 为文本框设置默认值 190 实例160 设置文本框的样式 191 实例161 文本域的滚动条 192 3.3 下拉列表的...

    C#编程经验技巧宝典

    100 <br>0158 如何将二进制数转换为十六进制数 100 <br>0159 如何实现0~9之间随机整数 101 <br>0160 如何实现0~1之间随机数 101 <br>0161 如何返回数字的绝对值 101 <br>5.2 控件数据处理...

Global site tag (gtag.js) - Google Analytics