Oracle不同行的某列字符串相加,去除重复值

Oracle不同行的某列字符串相加,去除重复值

有如下表SRS_B_CW_TEST
City People Make
广州   1        A
广州   2        B
广州   3        C
上海   4        A
上海   5        E
广州   6        A
上海   7        E

实现如下效果
City People Make
上海   16     AE
广州   12     ABC

我们一步一步的学习

(1)如果直接group by则只能数字sum,字符串无法相加
select City,sum(People) as People from SRS_B_CW_TEST group by City order by City
实现效果如下
City  People
上海   16
广州   12

(2)下面的写法错误,加不上Make
select City,sum(People) as People,Make from SRS_B_CW_TEST group by City order by City

(3)如果写成下面的sql语句
select City,sum(People) as People from SRS_B_CW_TEST group by City,Make order by City
实现效果如下
City  People
上海   4
上海   12
广州   7
广州   3
广州   2

(4)这时就可以加上Make
select City,sum(People) as People,Make from SRS_B_CW_TEST group by City,Make order by City
实现效果如下
City People Make
上海   4       A
上海   12     E
广州   7       A
广州   3      B
广州   2      C

(5)下面想办法实现Make列的字符串相加

(6)构造树,sql语句如下
select City,People,Make,
       row_number()over(order by City) RN,
       row_number()over(partition by City order by City) RM
from SRS_B_CW_TEST
实现效果如下
City  People  Make  RN   RM
上海    4         A      1    1
上海    5         E      2    2
上海    7         E      3    3
广州    6         A      4    1
广州    3         C      5    2
广州    2         B      6    3
广州    1         A      7    4

(7)有了树,就可以使用树型函数SYS_CONNECT_BY_PATH

(8)但是!如果按照(6)构造的树拼字符串的话会出问题,先写sql语句
select City,People,sys_connect_by_path(Make,',') as Make
from (
    select City,People,Make,
       row_number()over(order by City) RN,
       row_number()over(partition by City order by City) RM
    from SRS_B_CW_TEST
)
start with RM=1
connect by prior RN=RN-1
实现效果如下
City  People  Make
上海    4       ,A
上海    5       ,A,E
上海    7       ,A,E,E
广州    6       ,A,E,E,A
广州    3       ,A,E,E,A,C
广州    2       ,A,E,E,A,C,B
广州    1       ,A,E,E,A,C,B,A
广州    6       ,A
只有7条数据,怎么多了1,原来是RN没取好,不同组数字必须要'断开',导致connect by prior RN=RN-1处理时出了问题

(9)查找Oracle分析函数,我们发现一个函数对我们很有用rank(),于是我们修改6sql语句
select City,People,Make,
       rank()over(order by City) + row_number()over(order by City) RN,
       row_number()over(partition by City order by City) RM
from SRS_B_CW_TEST
实现效果如下
City  People  Make  RN   RM
上海    4         A     2     1
上海    5         E     3     2
上海    7         E     4     3
广州    6         A     8     1
广州    3         C     9     2
广州    2        B     10    3
广州    1        A     11    4
这样就'断开'

(10)重写(8)sql语句
select City,People,sys_connect_by_path(Make,',') as Make
from (
    select City,People,Make,
       rank()over(order by City) + row_number()over(order by City) RN,
       row_number()over(partition by City order by City) RM
    from SRS_B_CW_TEST
)
start with RM=1
connect by prior RN=RN-1
实现效果如下
City  People  Make
上海    4       ,A
上海    5       ,A,E
上海    7       ,A,E,E
广州    6       ,A
广州    3       ,A,C
广州    2       ,A,C,B
广州    1       ,A,C,B,A

(11)目的快要实现了,下面用sum求和,max函数取出最大值
select City,sum(People) as People,max(sys_connect_by_path(Make,',')) as Make
from (
    select City,People,Make,
       rank()over(order by City) + row_number()over(order by City) RN,
       row_number()over(partition by City order by City) RM
    from SRS_B_CW_TEST
)
start with RM=1
connect by prior RN=RN-1
group by
City
实现效果如下
City  People   Make
上海    16     ,A,E,E
广州    12     ,A,C,B,A

(12)去处第一个逗号,ltrim函数
select City,sum(People) as People,ltrim(max(sys_connect_by_path(Make,',')),',') as Make
from (
    select City,People,Make,
       rank()over(order by City) + row_number()over(order by City) RN,
       row_number()over(partition by City order by City) RM
    from SRS_B_CW_TEST
)
start with RM=1
connect by prior RN=RN-1
group by
City
实现效果如下
City  People   Make
上海    16     A,E,E
广州    12     A,C,B,A

(13)最后,去除重复的英文字母,这里需要借助函数的力量

(14)自己写一个函数
/************************************************************************************
创建者:曾浩
创建时间:2007-9-27
最新修改者:曾浩
最新修改时间:2007-9-27
用途:改进的split函数,
     
实现这样的效果
     
输入字符串123,123,234,345,234,345,456和字符串,
     
输出123,234,345,456
************************************************************************************/
create or replace function ZH_SPLIT(v_string in varchar2, v_delimiter in varchar2)
    return varchar2
is
    j int:=0;
    i int:=1;
    len_string int:=0;
    len_delimiter int:=0;
    str varchar2(4000);
    v_return varchar2(4000);
begin
    len_string := LENGTH(v_string);
    len_delimiter := LENGTH(v_delimiter);
    while j < len_string
    loop
        j := INSTR(v_string, v_delimiter, i);
        if j = 0 then
            j := len_string;
            str := SUBSTR(v_string, i);
            if instr(v_return, str) > 0 then
                null;
            else
                v_return:=v_return||str||',';
            end if;
            if i >= len_string then
                exit;
            end if;
        else
            str := SUBSTR(v_string, i, j - i);
            i := j + len_delimiter;
            if instr(v_return, str) > 0 then
                null;
            else
                v_return:=v_return||str||',';
            end if;
        end if;
    end loop;
    v_return := substr(v_return, 1, length(v_return)-1);
    return v_return;
end;

(15)调用这个函数
select City,sum(People) as People,ZH_SPLIT(ltrim(max(sys_connect_by_path(Make,',')),','),',') as Make
from (
    select City,People,Make,
       rank()over(order by City) + row_number()over(order by City) RN,
       row_number()over(partition by City order by City) RM
    from SRS_B_CW_TEST
)
start with RM=1
connect by prior RN=RN-1
group by
City
实现效果如下
City  People   Make
上海    16     A,E
广州    12     A,C,B

(16)大功告成!

 

你可能感兴趣的:(Oracle数据库)