Oracle列转行方法总结

ne3g 10年前

方法一:
----------------------------------------------------------------
---Muti-row to line(col2row)
----------------------------------------------------------------
create or replace type str_tab is table of varchar2(20);
/
grant all on str_tab to public;
create public synonym str_tab for str_tab;
create or replace function col2row(pv in str_tab) return varchar2
is
  ls varchar2(4000);
begin
  for i in 1..pv.count loop
    ls := ls || pv(i);
  end loop;
  return ls;
end;
/
grant execute on col2row to public;
create public synonym col2row for col2row;
----------------------------------------------------------------
--multi column,convert one column base on another column, for example
----------------------------------------------------------------
create table t(id number,name varchar2(10));
insert into t values(1,'Joan');
insert into t values(1,'Jack');
insert into t values(1,'Tom');
insert into t values(2,'Rose');
insert into t values(2,'Jenny');
---------------------------------------------------------------
SQL(c3dev)>select * from t;
        ID NAME
---------- ----------
         1 Joan
         1 Jack
         1 Tom
         2 Rose
         2 Jenny
---------------------------
--column to row
---------------------------
SQL(c3dev)>column names format a80;
SQL(c3dev)>set line 120
SQL(c3dev)>select t0.id,
  2     col2row(cast(multiset(select name from t where t.id = t0.id) as str_tab)) names
  3  from (select distinct id from t) t0;
        ID NAMES
---------- --------------------------------------------------------------------------------
         1 JoanJackTom
         2 RoseJenny

----------------------------------------------------------------
--single column,convert multil row to one row, for example
----------------------------------------------------------------
create table t1(name varchar2(20));
insert into t1 values('Chen');
insert into t1 values('Chuan');
insert into t1 values('Zhong');
SQL(c3dev)>select * from t1;
NAME
--------------------
Chen
Chuan
Zhong
---------------------------
--column to row
---------------------------
select col2row(cast(multiset(select name from t1) as str_tab)) names from t1 where rownum=1
SQL(c3dev)>select col2row(cast(multiset(select name from t1) as str_tab)) names from t1 where rownum=1;
NAMES
--------------------------------------------------------------------------------
ChenChuanZhong

--if need to add list separator
SQL(c3dev)>select col2row(cast(multiset(select name||' ' from t1) as str_tab)) names from t1 where rownum=1;
NAMES
--------------------------------------------------------------------------------
Chen  Chuan Zhong
 
方法二:
create table t2(col1 varchar2(10),col2 varchar2(10));
insert into t2 values('001','vl1');
insert into t2 values('001','vl2');
insert into t2 values('001','vl3');
insert into t2 values('002','vl1');
insert into t2 values('002','vl2');
SELECT COL1,LTRIM(MAX(SYS_CONNECT_BY_PATH(COL2,',')),',') COL2
 FROM
 (
 SELECT COL1,COL2,MIN(COL2) OVER(PARTITION BY COL1) COL2_MIN,
 (ROW_NUMBER() OVER(ORDER BY COL1,COL2))+(DENSE_RANK() OVER (ORDER BY COL1)) NUMID
 FROM T2
 )
 START WITH COL2=COL2_MIN CONNECT BY NUMID-1=PRIOR NUMID
 GROUP BY COL1;
COL1       COL2
---------- ----------------------------------------
001        vl1,vl2,vl3
002        vl1,vl2


 方法三(需要知道确定有几行):
 SELECT deptno, dname, emps
  FROM (SELECT d.deptno, d.dname,
               RTRIM
                  (   e.ename
                   || ', '
                   || LEAD (e.ename, 1) OVER (PARTITION BY d.deptno ORDER BY e.ename)
                   || ', '
                   || LEAD (e.ename, 2) OVER (PARTITION BY d.deptno ORDER BY e.ename)
                   || ', '
                   || LEAD (e.ename, 3) OVER (PARTITION BY d.deptno ORDER BY e.ename)
                   || ', '
                   || LEAD (e.ename, 4) OVER (PARTITION BY d.deptno ORDER BY e.ename)
                   || ', '
                   || LEAD (e.ename, 5) OVER (PARTITION BY d.deptno ORDER BY e.ename),
                   ', '
                  ) emps,
               ROW_NUMBER () OVER (PARTITION BY d.deptno ORDER BY e.ename) x
          FROM emp e, dept d
         WHERE d.deptno = e.deptno)
 WHERE x = 1
/
    DEPTNO DNAME          EMPS
---------- -------------- ----------------------------------------------------------------------
        10 ACCOUNTING     CLARK, KING, MILLER
        20 RESEARCH       ADAMS, FORD, JONES, SCOTT, SMITH
        30 SALES          ALLEN, BLAKE, JAMES, MARTIN, TURNER, WARD