表 A
ID COU
1  N1
2  N2
3  N3
....表CN1 N2 N3....
1  3  2
2  4  3
3  5  4
表C的列数与表A的行数一致(表C的列数根据表A行数增加,所以不能写死)。表C的列名与表A中各行中COU列的值保持一致。最终要得到如下结果集:ID NSUM 
1  6   (表C中列N1的和即:1+2+3)
2  12   (表C中列N2的和即:3+4+5)
3  9    (表C中列N3的和即:2+3+4)
....数据库是ORACLE,用存储过程实现。路过的有知道的,帮忙写下,谢谢!

解决方案 »

  1.   

    先表c列转行
    select A.ID,SUM(t.val)
    from A,
    (select 'A1' COU,A1  val
    from c 
    union all
    select 'A2' COU,A2   val
    from c 
    union all
    select 'A3' COU,A3  val
    from c )t
    where A.COU=t.COU
    group by A.ID
    ;
      

  2.   

    方法1:建函数
    CREATE OR REPLACE FUNCTION func_cou_val(p_col IN VARCHAR2)
    RETURN NUMBER
    AS
    v_sum number;
    BEGIN
      EXECUTE IMMEDIATE 'select sum('||p_col||') from c' INTO v_sum;
      RETURN v_sum;
    exception
    WHEN others THEN
      RETURN NULL;
    end;
    通过select id,func_cou_val(cou) from a;
    调用
    优点:使用方便方法二:存储过程
    --首先建一个临时表用来存放结果
    CREATE GLOBAL TEMPORARY TABLE tmp_a(ID NUMBER,nsum NUMBER)
    ON COMMIT PRESERVE ROWS;CREATE OR REPLACE PROCEDURE proc_cou_val
    AS
      sqlstr1 VARCHAR2(30000):='with t as(select';
      sqlstr2 varchar2(30000);
    BEGIN
      DELETE FROM tmp_a;
      FOR x IN(SELECT a.ID,b.column_name FROM A,user_tab_cols b 
        WHERE b.table_name(+)='C'
          AND A.cou=b.column_name(+)) loop
        IF x.column_name IS NULL THEN
          sqlstr2:=sqlstr2||'union all select '||to_char(x.ID)||',null from dual'||chr(10);
        ELSE
          sqlstr1:=sqlstr1||chr(10)||'sum('||x.column_name||') '||x.column_name||',';
          sqlstr2:=sqlstr2||'union all select '||to_char(x.ID)
            ||','||x.column_name||' from t'||chr(10);
        END IF;
      END loop;
      sqlstr1:=rtrim(sqlstr1,',')||' from c)';
      sqlstr2:=ltrim(sqlstr2,'union all ');
      EXECUTE IMMEDIATE 'insert into tmp_a'||chr(10)||sqlstr1||sqlstr2;
      commit;
    end;
    每次使用时,调用过程后,查询
    select * from tmp_a;优点:效率较高
      

  3.   

    !
       除了函数喝存储过程,可以用SQL语句实现!
      

  4.   

    用decode()函数可以很好地实现行列转换!!!
      

  5.   

    给你上个以前坛子里的高人编写的动态行传列存储过程,也许你能用到create or replace procedure row_to_col(tabname in varchar2,
                                      group_col in varchar2,
                                      column_col in varchar2,
                                      value_col in varchar2,
                                      Aggregate_func in varchar2 default 'max',
                                      colorder in varchar2 default null,
                                      roworder in varchar2 default null,
                                      when_value_null in varchar2 default null,
                                      viewname in varchar2 default 'v_tmp')
    Authid Current_User
    as
      sqlstr varchar2(2000):='create or replace view '||viewname||' as select '||group_col||' ';
      c1 sys_refcursor;
      v1 varchar2(100);
    begin
      open c1 for 'select distinct '||column_col||' from '||tabname||case when colorder is not null then ' order by '||colorder end;
      loop
        fetch c1 into v1;
        exit when c1%notfound;
        sqlstr:=sqlstr||chr(10)||','||case when when_value_null is not null then 'nvl(' end||
          Aggregate_func||'(decode(to_char('||column_col||'),'''||v1||''','||value_col||'))'||
          case when when_value_null is not null then chr(44) ||when_value_null||chr(41) end||'"'||v1||'"';
      end loop;
      close c1;
      sqlstr:=sqlstr||' from '||tabname||' group by '||group_col||case when roworder is not null then ' order by '||roworder end;
      execute immediate sqlstr;
    end row_to_col;
    这里修改了传入参数名,使其更容易理解。继续使用了创建视图这个方法,当然也可以改成用游标传出。 
    参数: 
    tabname 需要进行行转列操作的表名; 
    group_col 查询结果要按某列或某些列分组的字段名; 
    column_col 要从行转成列的字段; 
    value_col 需要聚合的值字段; 
    Aggregate_func 选用的聚合函数,可选,默认为max; 
    colorder 行转列后列的排序,可选; 
    roworder 行转列后记录的排序,可选; 
    when_value_null 若value_col字段的值聚合后为空,则转换成该值,可选; 
    viewname 创建的视图名称,可选,默认为v_tmp。 举例: 
    SQL code--测试数据
    create table rowtocol_test as
    select 2009 year,1 month,'部门1' dept,50000 expenditure from dual
    union all select 2009,2,'部门1',20000 from dual
    union all select 2009,2,'部门1',30000 from dual
    union all select 2010,1,'部门1',35000 from dual
    union all select 2009,2,'部门2',40000 from dual
    union all select 2009,3,'部门2',25000 from dual
    union all select 2010,2,'部门3',60000 from dual
    union all select 2009,2,'部门3',15000 from dual
    union all select 2009,2,'部门3',10000 from dual;我现在想根据year和month分组,将部门转成列。 
    SQL codeSQL> select * from rowtocol_test;
     
          YEAR      MONTH DEPT  EXPENDITURE
    ---------- ---------- ----- -----------
          2009          1 部门1       50000
          2009          2 部门1       20000
          2009          2 部门1       30000
          2010          1 部门1       35000
          2009          2 部门2       40000
          2009          3 部门2       25000
          2010          2 部门3       60000
          2009          2 部门3       15000
          2009          2 部门3       10000
     
    9 rows selected
     
    SQL> execute row_to_col('rowtocol_test','year,month','dept','expenditure');PL/SQL procedure successfully completed
     
    SQL> select * from v_tmp;
     
          YEAR      MONTH        部门1        部门3        部门2
    ---------- ---------- ---------- ---------- ----------
          2009          1      50000            
          2010          1      35000            
          2009          3                            25000
          2009          2      30000      15000      40000
          2010          2                 60000 
     
    SQL> 这个结果可能不是我们想要的,重新调用过程,使用几个可选参数 
    SQL codeSQL> execute row_to_col('rowtocol_test','year,month','dept','expenditure',Aggregate_func => 'sum',colorder => 'dept',roworder => '1,2',when_value_null => '0');
     
    PL/SQL procedure successfully completed
     
    SQL> select * from v_tmp;
     
          YEAR      MONTH        部门1        部门2        部门3
    ---------- ---------- ---------- ---------- ----------
          2009          1      50000          0          0
          2009          2      50000      40000      25000
          2009          3          0      25000          0
          2010          1      35000          0          0
          2010          2          0          0      60000
     
    SQL> 进行行转列的也可以是视图 
    SQL codeSQL> create view view_rowtocol as select * from rowtocol_test where year=2009;
     
    View created
     
    SQL> execute row_to_col('view_rowtocol','year,month','dept','expenditure',Aggregate_func => 'sum',colorder => 'dept',roworder => '1,2',when_value_null => '0');
     
    PL/SQL procedure successfully completed
     
    SQL> select * from v_tmp;
     
          YEAR      MONTH        部门1        部门2        部门3
    ---------- ---------- ---------- ---------- ----------
          2009          1      50000          0          0
          2009          2      50000      40000      25000
          2009          3          0      25000          0
     
    SQL>