zoukankan      html  css  js  c++  java
  • 关于分组后字段拼接的问题 (Oracle)

    -----关于分组后字段拼接的问题

    来自:www.itpub.net 

    最近在论坛上,经常会看到关于分组后字段拼接的问题,
    大概是类似下列的情形:
    SQL> select no,q from test
    2 /

    NO Q
    ---------- ------------------------------
    001 n1
    001 n2
    001 n3
    001 n4
    001 n5
    002 m1
    003 t1
    003 t2
    003 t3
    003 t4
    003 t5
    003 t6

    12 rows selected

    最后要得到类似于如下的结果:
    001 n1;n2;n3;n4;n5
    002 m1
    003 t1;t2;t3;t4;t5;t6

    通常大家都认为这类问题无法用一句SQL解决,本来我也这么认为,可是今天无意中突然有了灵感,原来是可以这么做的:
    前几天有人提到过sys_connect_by_path的用法,我想这里是不是也能用到这个方法,如果能做到的话,不用函数或存贮过程也可以做到了;要用到sys_connect_by_path,首先要自己构建树型的结构,并且树的每个分支都是单根的,例如1-〉2-〉3-〉4,不会存在1-〉2,1-〉3的情况;
    我是这么构建树,很简单的,看下面的结果就会知道了:
    SQL> select no,q,rn,lead(rn) over(partition by no order by rn) rn1
    2 from (select no,q,row_number() over(order by no,q desc) rn from test)
    3 /

    NO Q RN RN1
    ---------- ------------------------------ ---------- ----------
    001 n5 1 2
    001 n4 2 3
    001 n3 3 4
    001 n2 4 5
    001 n1 5
    002 m1 6
    003 t6 7 8
    003 t5 8 9
    003 t4 9 10
    003 t3 10 11
    003 t2 11 12
    003 t1 12

    12 rows selected

    有了这个树型的结构,接下来的事就好办了,只要取出拥有全路径的那个path,问题就解决了,先看no=‘001’的分组:
    select no,sys_connect_by_path(q,';') result from
    (select no,q,rn,lead(rn) over(partition by no order by rn) rn1
    from (select no,q,row_number() over(order by no,q desc) rn from test)
    )
    start with no = '001' and rn1 is null connect by rn1 = prior rn
    SQL>
    6 /

    NO RESULT
    ---------- --------------------------------------------------------------------------------
    001 ;n1
    001 ;n1;n2
    001 ;n1;n2;n3
    001 ;n1;n2;n3;n4
    001 ;n1;n2;n3;n4;n5

    上面结果的最后1条就是我们要得结果了
    要得到每组的结果,可以下面这样

    代码:

    select t
    .*,
           (
            
    select max(sys_connect_by_path(q,';')) result from
                   
    (select no,q,rn,lead(rn) over(partition by no order by rn) rn1
                   from
    (select no,q,row_number() over(order by no,q desc) rn from test)
                   )
            
    start with no = t.no and rn1 is null connect by rn1 = prior rn
           
    ) value
    from
    (select distinct no from test)  



    SQL>
    10 /

    NO VALUE
    ---------- --------------------------------------------------------------------------------
    001 ;n1;n2;n3;n4;n5
    002 ;m1
    003 ;t1;t2;t3;t4;t5;t6

    对上面结果稍加处理就可以了,希望对大家有帮助:)

    稍微改进下:

    代码:


    select no
    ,max(sys_connect_by_path(q,';')) result from
    (
      
    select no,q,rn,lead(rn) over(partition by no order by rn)
    rn1
       from
    (
              
    select no,q,row_number() over(order by no,q desc)
    rn from test
            
    )
    )
    start with rn1 is null
    connect by rn1
    =
    prior rn
    group by no


    改进下算法,少一层嵌套查询,效率会好些:

    代码:

    select no
    ,max(sys_connect_by_path(q,';')) result from
    (
           
    select no,q,(row_number() over(order by no,q desc) + rank() over(order by no))
    rn
           from test
    )
    connect by rn-1 =
    prior rn
    group by no
    ;




  • 相关阅读:
    45. 跳跃游戏 II
    BIO,AIO,NIO
    sqlyog连接阿里云mysql
    Hive的数据表HDFS的关系。
    云计算和虚拟机
    oracle入门笔记
    程序员开发协作管理工具
    IT行业的新思想来源
    docker所需的os基础
    docker源码和原理探究
  • 原文地址:https://www.cnblogs.com/jimeper/p/358353.html
Copyright © 2011-2022 走看看