zoukankan      html  css  js  c++  java
  • 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
        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,去掉最前面的那个分号,完成。

    来源:http://oracle.chinaitlab.com/PLSQL/935588_2.html

  • 相关阅读:
    iOS应用崩溃日志分析
    iOS应用崩溃日志分析
    iOS 获取一个类的所有方法
    iOS 获取一个类的所有方法
    UVa 818Cutting Chains (暴力dfs+位运算+二进制法)
    UVa 1374 Power Calculus (IDA*或都打表)
    UVa 10603 Fill (暴力BFS+优先队列)
    HDU 1272 小希的迷宫 (并查集)
    HDU 1060 Leftmost Digit (数学log)
    UVa 1599 Ideal Path (两次BFS)
  • 原文地址:https://www.cnblogs.com/rickie4you/p/3483745.html
Copyright © 2011-2022 走看看