This is a frequently asked question “How to display multiple rows in a single row as a delimited string”. It is basically string aggregation.
I will demonstrate the various techniques of string aggregation in Oracle SQL using the standard SCOTT.EMP table.
Oracle database 9i and up:
ROW_NUMBER() and SYS_CONNECT_BY_PATH
SQL> SELECT deptno,
2 LTRIM(MAX(SYS_CONNECT_BY_PATH(ename,','))
3 KEEP (DENSE_RANK LAST ORDER BY rn),',') AS emp_name
4 FROM
5 (SELECT deptno,
6 ename,
7 ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) rn,
8 ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 rn_lag
9 FROM emp
10 )
11 GROUP BY deptno
12 CONNECT BY rn_lag = PRIOR rn
13 AND deptno = PRIOR deptno
14 START WITH rn = 1
15 ORDER BY deptno;
DEPTNO EMP_NAME
---------- ----------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
Oracle database 10g and up:
MODEL clause
SQL> select deptno
2 , rtrim(ename,',') enames
3 from ( select deptno
4 , ename
5 , rn
6 from emp
7 model
8 partition by (deptno)
9 dimension by (row_number() over
10 (partition by deptno order by ename) rn
11 )
12 measures (cast(ename as varchar2(40)) ename)
13 rules
14 ( ename[any] order by rn desc = ename[cv()]||','||ename[cv()+1]
15 )
16 )
17 where rn = 1
18 order by deptno
19 /
DEPTNO ENAMES
---------- ----------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
Oracle database 11g Release 2 and up:
LISTAGG
SQL> SELECT deptno,
2 LISTAGG(ename, ',') WITHIN GROUP (ORDER BY ename) AS emp_name
3 FROM emp
4 GROUP BY deptno
5 ORDER BY deptno;
DEPTNO EMP_NAME
---------- ----------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
Hope it helps!
Filed under: Oracle String Aggregation Tagged: aggregation, listagg, model clause, row_number, SQL, string aggregation, sys_connect_by_path
