首页 运维知识 在Oracle中用一条Sql实现任意的行转列拼接/多行拼接

在Oracle中用一条Sql实现任意的行转列拼接/多行拼接

表结构和数据如下(表名Test): NO VALUE NAME 1 a 测试1 1 b 测试2 1 c 测试3 1 d 测试4 2 e 测试5 4 f 测试6 4 g 测试7 Sq…

表结构和数据如下(表名Test):
    NO VALUE  NAME
    1       a       测试1
    1       b       测试2
    1       c       测试3
    1       d       测试4
    2       e       测试5
    4       f        测试6
    4       g       测试7
    Sql语句:
    select No,
    ltrim(max(sys_connect_by_path(Value, \';\')), \';\') as Value,
    ltrim(max(sys_connect_by_path(Name, \';\')), \';\') as Name
    from (select No,
    Value,
    Name,
    rnFirst,
    lead(rnFirst) over(partition by No order by rnFirst) rnNext
    from (select a.No,
    a.Value,
    a.Name,
    row_number() over(order by a.No, a.Value desc) rnFirst
    from Test a) tmpTable1) tmpTable2
    start with rnNext is null
    connect by rnNext = prior rnFirst
    group by No;
    检索结果如下:
    NO VALUE    NAME
    1    a;b;c;d   测试1;测试2;测试3;测试4
    2    e            测试5
    4    f;g          测试6;测试7
    简单解释一下那个Sql吧:
    1、最内层的Sql(即表tmpTable1),按No和Value排序,并列出行号:
    select a.No,
    a.Value,
    a.Name,
    row_number() over(order by a.No, a.Value desc) rnFirst
    from Test a
    该语句结果如下:
    NO VALUE NAME RNFIRST
    1     d       测试4     1
    1     c       测试3     2
    1     b       测试2     3
    1     a       测试1     4
    2     e       测试5     5
    4     g       测试7     6
    4     f       测试6     7
    2、外层的Sql(即表tmpTable2),根据No分区,取出当前行对应的下一条记录的行号字段:
    select No,
    Value,
    Name,
    rnFirst,
    lead(rnFirst) over(partition by No order by rnFirst) rnNext
    from (这里是tmpTable1的SQL) tmpTable1
    lead(rnFirst):取得下一行记录的rnFirst字段
    over(partition by No order by rnFirst) 按rnFirst排序,并按No分区,分区就是如果下一行的No字段与当前行的No字段不相等时,不取下一行记录显示
   该语句结果如下:

    NO VALUE NAME RNFIRST RNNEXT
    1     d        测试4     1         2
    1     c        测试3      2         3
    1     b        测试2     3         4
    1     a        测试1     4         NULL
    2     e        测试5     5         NULL
    4     g        测试7     6         7
    4     f         测试6     7         NULL

    3、最后就是最外层的sys_connect_by_path函数与start递归了
    sys_connect_by_path(Value, \';\')
    start with rnNext is null
    connect by rnNext = prior rnFirst
    这个大概意思就是从rnNext为null的那条记录开始,递归查找,
    如果前一记录的rnFirst字段等于当前记录的rnNext字段,就把2条记录的Value用分号连接起来,
    大家可以先试试下面这个没有Max和Group的Sql:

    select No,
    sys_connect_by_path(Value, \';\') as Value,
    sys_connect_by_path(Name, \';\') as Name
    from (select No,
    Value,
    Name,
    rnFirst,
    lead(rnFirst) over(partition by No order by rnFirst) rnNext
    from (select a.No,
    a.Value,
    a.Name,
    row_number() over(order by a.No, a.Value desc) rnFirst
    from Test a) tmpTable1) tmpTable2
    start with rnNext is null
    connect by rnNext = prior rnFirst

    结果是:
    NO VALUE       NAME
    1     ;a            ;测试1
    1     ;a;b         ;测试1;测试2
    1     ;a;b;c     ;测试1;测试2;测试3
    1     ;a;b;c;d  ;测试1;测试2;测试3;测试4
    2     ;e            ;测试5
    4     ;f             ;测试6
    4     ;f;g          ;测试6;测试7

    可以看到,每个No的最后一条记录就是我们要的了
    所以在sys_connect_by_path外面套一个Max,再加个Group by No,得到的结果就是行转列的结果了
    最后再加一个Ltrim,去掉最前面的那个分号,完成。
免责声明:文章内容不代表本站立场,本站不对其内容的真实性、完整性、准确性给予任何担保、暗示和承诺,仅供读者参考,文章版权归原作者所有。如本文内容影响到您的合法权益(内容、图片等),请及时联系本站,我们会及时删除处理。

作者: 小小编

为您推荐

dell R710 更换raid卡后,raid卡信息没有了,处理方案

dell R710 更换raid卡后,raid卡信息没有了,处理方案

1.将一台服务器(A)的硬盘依次拔出,按相同顺序插入另一台同样配置的服务器(B) 2.启动服务器(B) 3.按提示键盘按...
PL SQL Developer 13连接Oracle数据库并导出数据详细操作教程方法

PL SQL Developer 13连接Oracle数据库并导出数据详细操作教程方法

下载 并安装 PL SQL Developer 13,默认支持中文语言 ========================...
关于一条sql语句在mysql中是如何执行的

关于一条sql语句在mysql中是如何执行的

最近开始在学习mysql相关知识,自己根据学到的知识点,根据自己的理解整理分享出来,本篇文章会分析下一个sql语句在my...
关于sql注入姿势总结(mysql)

关于sql注入姿势总结(mysql)

前言 学习了sql注入很长时间,但是仍然没有系统的了解过,这次总结一波,用作学习的资料。 从注入方法分:基于报错、基于布...
关于Oracle SQL外连接

关于Oracle SQL外连接

SQL提供了多种类型的连接方式,它们之间的区别在于:从相互交叠的不同数据集合中选择用于连接的行时所采用的方法不同。 连接...

发表回复

返回顶部