关于Oralce的行列转换
现在有个表的结构如下
clum :  id   name1  number1  name2  number2   name3  number3 ......  name30  number30
date :  001  n1     100      n2     200       n3     300    .......  n30     300000
现在想通过SQL处理变成
clum   id  name   number
data   001 n1     100
       001 n2     200
       001 n3     300
       ......
       001 n30    300000
请问这个应该如何处理 
现在我的方法是
select id name1 number1 from table
union all
select id name2 number2 from table
union all
.........
select id name30 number30 from table但是这样的做法感觉不太合适
问问大家有没有 比较简练的解决方法?

解决方案 »

  1.   

    Tom写的print_table
    PHP code:--------------------------------------------------------------------------------
    create or replace
    procedure print_table
    ( p_query in varchar2,
      p_date_fmt in varchar2 default 'dd-mon-yyyy hh24:mi:ss' )
                                                                                     
                                               
    -- this utility is designed to be installed ONCE in a database and used
    -- by all.  Also, it is nice to have roles enabled so that queries by
    -- DBA's that use a role to gain access to the DBA_* views still work
    -- that is the purpose of AUTHID CURRENT_USER
    AUTHID CURRENT_USER
    is
        l_theCursor     integer default dbms_sql.open_cursor;
        l_columnValue   varchar2(4000);
        l_status        integer;
        l_descTbl       dbms_sql.desc_tab;
        l_colCnt        number;
        l_cs            varchar2(255);
        l_date_fmt      varchar2(255);
                                                                                     
                                               
        -- small inline procedure to restore the sessions state
        -- we may have modified the cursor sharing and nls date format
        -- session variables, this just restores them
        procedure restore
        is
        begin
           if ( upper(l_cs) not in ( 'FORCE','SIMILAR' ))
           then
               execute immediate
               'alter session set cursor_sharing=exact';
           end if;
           if ( p_date_fmt is not null )
           then
               execute immediate
                   'alter session set nls_date_format=''' || l_date_fmt || '''';
           end if;
           dbms_sql.close_cursor(l_theCursor);
        end restore;
    begin
        -- I like to see the dates print out with times, by default, the
        -- format mask I use includes that.  In order to be "friendly"
        -- we save the date current sessions date format and then use
        -- the one with the date and time.  Passing in NULL will cause
        -- this routine just to use the current date format
        if ( p_date_fmt is not null )
        then
           select sys_context( 'userenv', 'nls_date_format' )
             into l_date_fmt
             from dual;
                                                                                     
                                               
           execute immediate
           'alter session set nls_date_format=''' || p_date_fmt || '''';
        end if;
                                                                                     
                                               
        -- to be bind variable friendly on this ad-hoc queries, we
        -- look to see if cursor sharing is already set to FORCE or
        -- similar, if not, set it so when we parse -- literals
        -- are replaced with binds
        if ( dbms_utility.get_parameter_value
             ( 'cursor_sharing', l_status, l_cs ) = 1 )
        then
            if ( upper(l_cs) not in ('FORCE','SIMILAR'))
            then
                execute immediate
               'alter session set cursor_sharing=force';
            end if;
        end if;
                                                                                     
                                               
        -- parse and describe the query sent to us.  we need
        -- to know the number of columns and their names.
        dbms_sql.parse(  l_theCursor,  p_query, dbms_sql.native );
        dbms_sql.describe_columns
        ( l_theCursor, l_colCnt, l_descTbl );
                                                                                     
                                               
        -- define all columns to be cast to varchar2's, we
        -- are just printing them out
        for i in 1 .. l_colCnt loop
            if ( l_descTbl(i).col_type not in ( 113 ) )
            then
                dbms_sql.define_column
                (l_theCursor, i, l_columnValue, 4000);
            end if;
        end loop;
                                                                                     
                                               
        -- execute the query, so we can fetch
        l_status := dbms_sql.execute(l_theCursor);
                                                                                     
                                               
        -- loop and print out each column on a separate line
        -- bear in mind that dbms_output only prints 255 characters/line
        -- so we'll only see the first 200 characters by my design...
        while ( dbms_sql.fetch_rows(l_theCursor) > 0 )
        loop
            for i in 1 .. l_colCnt loop
                if ( l_descTbl(i).col_type not in ( 113 ) )
                then
                    dbms_sql.column_value
                    ( l_theCursor, i, l_columnValue );
                    dbms_output.put_line
                    ( rpad( l_descTbl(i).col_name, 30 )
                    || ': ' ||
                    substr( l_columnValue, 1, 200 ) );
                end if;
            end loop;
            dbms_output.put_line( '----------------- );
        end loop;
                                                                                     
                                               
        -- now, restore the session state, no matter what
        restore;
    exception
        when others then
            restore;
            raise;
    end;
    /
      

  2.   

    SQL> SET SERVEROUT ON SIZE 100000
    SQL> exec print_table('select * from emp');
    EMPNO                         : 7369
    ENAME                         : SMITH
    JOB                           : CLERK
    MGR                           : 7902
    HIREDATE                      : 17-dec-1980 00:00:00
    SAL                           : 800
    COMM                          :
    DEPTNO                        : 20
    -----------------
    EMPNO                         : 7499
    ENAME                         : ALLEN
    JOB                           : SALESMAN
    MGR                           : 7698
    HIREDATE                      : 20-feb-1981 00:00:00
    SAL                           : 1600
    COMM                          : 300
    DEPTNO                        : 30
    -----------------
    EMPNO                         : 7521
    ENAME                         : WARD
    JOB                           : SALESMAN
    MGR                           : 7698
    HIREDATE                      : 22-feb-1981 00:00:00
    SAL                           : 1250
    COMM                          : 500
    DEPTNO                        : 30
    -----------------
    EMPNO                         : 7566
    ENAME                         : JONES
    JOB                           : MANAGER
    MGR                           : 7839
    HIREDATE                      : 02-apr-1981 00:00:00
    SAL                           : 2975
    COMM                          :
    DEPTNO                        : 20
    -----------------
    EMPNO                         : 7654
    ENAME                         : MARTIN
    JOB                           : SALESMAN
    MGR                           : 7698
    HIREDATE                      : 28-sep-1981 00:00:00
    SAL                           : 1250
    COMM                          : 1400
    DEPTNO                        : 30
    -----------------
    EMPNO                         : 7698
    ENAME                         : BLAKE
    JOB                           : MANAGER
    MGR                           : 7839
    HIREDATE                      : 01-may-1981 00:00:00
    SAL                           : 2850
    COMM                          :
    DEPTNO                        : 30
    -----------------
    EMPNO                         : 7782
    ENAME                         : CLARK
    JOB                           : MANAGER
    MGR                           : 7839
    HIREDATE                      : 09-jun-1981 00:00:00
    SAL                           : 2450
    COMM                          :
    DEPTNO                        : 10
    -----------------
    EMPNO                         : 7788
    ENAME                         : SCOTT
    JOB                           : ANALYST
    MGR                           : 7566
    HIREDATE                      : 19-apr-1987 00:00:00
    SAL                           : 3000
    COMM                          :
    DEPTNO                        : 20
    -----------------
    EMPNO                         : 7839
    ENAME                         : KING
    JOB                           : PRESIDENT
    MGR                           :
    HIREDATE                      : 17-nov-1981 00:00:00
    SAL                           : 5000
    COMM                          :
    DEPTNO                        : 10
    -----------------
    EMPNO                         : 7844
    ENAME                         : TURNER
    JOB                           : SALESMAN
    MGR                           : 7698
    HIREDATE                      : 08-sep-1981 00:00:00
    SAL                           : 1500
    COMM                          : 0
    DEPTNO                        : 30
    -----------------
    EMPNO                         : 7876
    ENAME                         : ADAMS
    JOB                           : CLERK
    MGR                           : 7788
    HIREDATE                      : 23-may-1987 00:00:00
    SAL                           : 1100
    COMM                          :
    DEPTNO                        : 20
    -----------------
    EMPNO                         : 7900
    ENAME                         : JAMES
    JOB                           : CLERK
    MGR                           : 7698
    HIREDATE                      : 03-dec-1981 00:00:00
    SAL                           : 950
    COMM                          :
    DEPTNO                        : 30
    -----------------
    EMPNO                         : 7902
    ENAME                         : FORD
    JOB                           : ANALYST
    MGR                           : 7566
    HIREDATE                      : 03-dec-1981 00:00:00
    SAL                           : 3000
    COMM                          :
    DEPTNO                        : 20
    -----------------
    EMPNO                         : 7934
    ENAME                         : MILLER
    JOB                           : CLERK
    MGR                           : 7782
    HIREDATE                      : 23-jan-1982 00:00:00
    SAL                           : 1300
    COMM                          :
    DEPTNO                        : 10
    -----------------
     
    PL/SQL procedure successfully completed.
     
    SQL>
      

  3.   

    上面过程有几个错的地方更新一下:
    create or replace
    procedure print_table
    ( p_query in varchar2,
      p_date_fmt in varchar2 default 'dd-mon-yyyy hh24:mi:ss' )
    -- this utility is designed to be installed ONCE in a database and used
    -- by all.  Also, it is nice to have roles enabled so that queries by
    -- DBA's that use a role to gain access to the DBA_* views still work
    -- that is the purpose of AUTHID CURRENT_USER
    AUTHID CURRENT_USER
    is
        l_theCursor    integer default dbms_sql.open_cursor;
        l_columnValue  varchar2(4000);
        l_status        integer;
        l_descTbl      dbms_sql.desc_tab;
        l_colCnt        number;
        l_cs            varchar2(255);
        l_date_fmt      varchar2(255);
        -- small inline procedure to restore the sessions state
        -- we may have modified the cursor sharing and nls date format
        -- session variables, this just restores them
        procedure restore
        is
        begin
          if ( upper(l_cs) not in ( 'FORCE','SIMILAR' ))
          then
              execute immediate 'alter session set cursor_sharing=exact';
          end if;
          if ( p_date_fmt is not null )
          then
              execute immediate
                  'alter session set nls_date_format='''||l_date_fmt||'''';
          end if;
          dbms_sql.close_cursor(l_theCursor);
        end restore;
    begin
        -- I like to see the dates print out with times, by default, the
        -- format mask I use includes that.  In order to be
        -- we save the date current sessions date format and then use
        -- the one with the date and time.  Passing in NULL will cause
        -- this routine just to use the current date format
        if ( p_date_fmt is not null )
        then
          select sys_context( 'userenv', 'nls_date_format' )
            into l_date_fmt
            from dual;
          execute immediate
          'alter session set nls_date_format='''||p_date_fmt||'''';
        end if;
        -- to be bind variable friendly on this ad-hoc queries, we
        -- look to see if cursor sharing is already set to FORCE or
        -- similar, if not, set it so when we parse -- literals
        -- are replaced with binds
        if ( dbms_utility.get_parameter_value
            ( 'cursor_sharing', l_status, l_cs ) = 1 )
        then
            if ( upper(l_cs) not in ('FORCE','SIMILAR'))
            then
                execute immediate
              'alter session set cursor_sharing=force';
            end if;
        end if;
        -- parse and describe the query sent to us.  we need
        -- to know the number of columns and their names.
        dbms_sql.parse(  l_theCursor,  p_query, dbms_sql.native );
        dbms_sql.describe_columns
        ( l_theCursor, l_colCnt, l_descTbl );
        -- define all columns to be cast to varchar2's, we
        -- are just printing them out
        for i in 1 .. l_colCnt loop
            if ( l_descTbl(i).col_type not in ( 113 ) )
            then
                dbms_sql.define_column
                (l_theCursor, i, l_columnValue, 4000);
            end if;
        end loop;
        -- execute the query, so we can fetch
        l_status := dbms_sql.execute(l_theCursor);
        -- loop and print out each column on a separate line
        -- bear in mind that dbms_output only prints 255 characters/line
        -- so we'll only see the first 200 characters by my design...
        while ( dbms_sql.fetch_rows(l_theCursor) > 0 )
        loop
            for i in 1 .. l_colCnt loop
                if ( l_descTbl(i).col_type not in ( 113 ) )
                then
                    dbms_sql.column_value
                    ( l_theCursor, i, l_columnValue );
                    dbms_output.put_line
                    ( rpad( l_descTbl(i).col_name, 30 )
                    ||': '||
                    substr( l_columnValue, 1, 200 ) );
                end if;
            end loop;
            dbms_output.put_line( '-----------------' );
        end loop;
        -- now, restore the session state, no matter what
        restore;
    exception
        when others then
            restore;
            raise;
    end;
    /
      

  4.   

    tom kyte大师写的,贴出来给大家一起学习