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
    ;




  • 相关阅读:
    第二次作业循环语句
    c语言01次作业分支,顺序结构
    PAT 1027. Colors in Mars
    PAT 1026 Table Tennis
    PAT 1035 Password
    PAT 1038. Recover the Smallest Number
    PAT 1028 List Sorting (25)
    PAT 1041 Be Unique (20)
    PAT 1025 PAT Ranking
    1037. Magic Coupon
  • 原文地址:https://www.cnblogs.com/jimeper/p/358353.html
Copyright © 2011-2022 走看看