Row to column
A Friend asked how to convert multi-row to one row that have multi-column with delimiter in DB2. Such as:
c1 ---- a b c
==>
c2 ---------- a | b | c
Actually, There are 2 different requirements on this point. The first one is that the multi-row number is limited and could be referred as a flag. Such as:
c1 c2 ---- ---- 10 Jan 21 Feb 88 Mar ... ... 04 Dec
The second one is that the multi-row number is unlimited or can not be referred with any character.
There's the way that uses pure SQL to implement the first requirement. Here's a sample: changing row to column
select emp_id, sum(case month(pay_date) when 1 then salary else 0 end) Jan, sum(case month(pay_date) when 2 then salary else 0 end) Feb, sum(case month(pay_date) when 3 then salary else 0 end) Mar, sum(case month(pay_date) when 4 then salary else 0 end) Apr, sum(case month(pay_date) when 5 then salary else 0 end) May, sum(case month(pay_date) when 6 then salary else 0 end) Jun, sum(case month(pay_date) when 7 then salary else 0 end) Jul, sum(case month(pay_date) when 8 then salary else 0 end) Aug, sum(case month(pay_date) when 9 then salary else 0 end) Sep, sum(case month(pay_date) when 10 then salary else 0 end) Oct, sum(case month(pay_date) when 11 then salary else 0 end) Nov, sum(case month(pay_date) when 12 then salary else 0 end) Dec, sum(salary) total from emp_salary group by emp_id
To the 2nd requirement, the only way is to write use-defined function for it. It accepts a cursor and output one row. Here's a sample in Oracle.
SELECT
a.deptno,
a.dname,
a.loc, rowtocol('SELECT DISTINCT job
FROM emp WHERE deptno = ' ||a.deptno) as jobs
FROM dept a;
CREATE OR REPLACE FUNCTION rowtocol( p_slct IN VARCHAR2, p_dlmtr IN VARCHAR2 DEFAULT ',' ) RETURN VARCHAR2 AUTHID CURRENT_USER AS ... TYPE c_refcur IS REF CURSOR; lc_str VARCHAR2(4000); lc_colval VARCHAR2(4000); c_dummy c_refcur; l number; BEGIN OPEN c_dummy FOR p_slct; LOOP FETCH c_dummy INTO lc_colval; EXIT WHEN c_dummy%NOTFOUND; lc_str := lc_str || p_dlmtr || lc_colval; END LOOP; CLOSE c_dummy; RETURN SUBSTR(lc_str,2); /* EXCEPTION WHEN OTHERS THEN lc_str := SQLERRM; IF c_dummy%ISOPEN THEN CLOSE c_dummy; END IF; RETURN lc_str; */ END;
Update 2008-08-01
A little update on the topic.
What if when the function SUM() is not allowed for the data type? See below example:
with tmp(c1,c2,c3) as ( values (1,'a',1), (1,'b',2) ) select * from tmp @
C1 C2 C3 ----------- -- ----------- 1 a 1 1 b 2 2 record(s) selected.
The answer is we could use MAX(), MIN() like below:
select c1, max(case c3 when 1 then c2 end), max(case c3 when 2 then c2 end) from tmp group by c1@
C1 2 3 ----------- - - 1 a b 1 record(s) selected.


