This new LISTAGG built-in feature was released in Oracle 11g Release 2 a function that will enable us to perform string aggregation naively. String aggregation is been popular technique and different methods prior to Oracle 11g.
The LISTAGG function has the following syntax
LISTAGG( [,]) WITHIN GROUP (ORDER BY ) [OVER (PARTITION BY )]
- the column or expression to be aggregated;
- the WITHIN GROUP keywords;
- the ORDER BY clause within the grouping.
What is string aggregation?
String aggregation is the grouping and concatenation of rows of data into a single row per group. For example:
DEPTNO ENAME
——— ———-
10 CLARK
10 KING
10 MILLER
20 ADAMS
20 FORD
20 JONES
Using the Emp table from the scott user:
SELECT deptno
,LISTAGG(ename, ‘,’) WITHIN GROUP (ORDER BY ename) AS employees
FROM emp
GROUP BY deptno;
DEPTNO EMPLOYEES
——— ————————-
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES
We can see that the employee names have been grouped and concatenated into a single per group.
LISTAGG as an analytic function
As with many aggregate functions, LISTAGG can be converted to an analytic function by adding the OVER() clause. The following example demonstrates the analytic equivalent of our previous example (for each department, aggregate employee names in hire date order).
SQL> SELECT deptno
2 , ename
3 , hiredate
4 , LISTAGG(ename, ‘,’)
5 WITHIN GROUP (ORDER BY hiredate)
6 OVER (PARTITION BY deptno) AS employees
7 FROM emp;
DEPTNO ENAME HIREDATE EMPLOYEES
———- ———- ———– ————————————-
10 CLARK 09/06/1981 CLARK,KING,MILLER
10 KING 17/11/1981 CLARK,KING,MILLER
10 MILLER 23/01/1982 CLARK,KING,MILLER
20 SMITH 17/12/1980 SMITH,JONES,FORD,SCOTT,ADAMS
20 JONES 02/04/1981 SMITH,JONES,FORD,SCOTT,ADAMS
20 FORD 03/12/1981 SMITH,JONES,FORD,SCOTT,ADAMS
20 SCOTT 19/04/1987 SMITH,JONES,FORD,SCOTT,ADAMS
20 ADAMS 23/05/1987 SMITH,JONES,FORD,SCOTT,ADAMS
30 ALLEN 20/02/1981 ALLEN,WARD,BLAKE,TURNER,MARTIN,JAMES
30 WARD 22/02/1981 ALLEN,WARD,BLAKE,TURNER,MARTIN,JAMES
30 BLAKE 01/05/1981 ALLEN,WARD,BLAKE,TURNER,MARTIN,JAMES
30 TURNER 08/09/1981 ALLEN,WARD,BLAKE,TURNER,MARTIN,JAMES
30 MARTIN 28/09/1981 ALLEN,WARD,BLAKE,TURNER,MARTIN,JAMES
30 JAMES 03/12/1981 ALLEN,WARD,BLAKE,TURNER,MARTIN,JAMES
Prior to Oracle 11g Rel 2 – STRAGG and WM_CONCAT
LISTAGG is similar to WM_CONCAT and STRAGG, but the difference been that it is a documented and supported function by oracle. This function is a part of Oracle 11g Release 2 version.
Additional features of this function have over previous functions are:
1) Can select your own separator. The default value is NULL
2) Can get the ordered list by ordering the column
3) Supported by Oracle, can be used in Production system
4) Much faster than WM_CONCAT and little better than STRAGG function
I had a project building a process that uses the LISTAGG function in a generic way. Real Example:
The process needed to create a list of values based on the Column_Name from the table provided to be used in dynamic sql to return correct records based on criteria and list of values provided. The columns had a naming convention of SEQ in name to allow its additional columns sequences needed for new markets. The codes snipped below are simplified to help illustrate the contents of the discussion of using the LISTAGG.
The code snipped below retrieved the Column Names for the string in the dynamic sql:
SELECT REPLACE (LISTAGG (‘NVL(‘ || COLUMN_NAME || ‘,0)’, ‘,’)
WITHIN GROUP (ORDER BY COLUMN_NAME),
‘,NVL’,’||”,”||NVL’) AS markets
INTO V_MARKET_LISTS
FROM ALL_TAB_COLS
WHERE table_name = ‘QUOTE_DATA’
AND OWNER = ‘SCHEMA’
AND column_name LIKE ‘%SEQ%’
ORDER BY COLUMN_NAME;
The snippet query to retrieve values using the v_market_list provide from above query:
v_work_market :=
‘SELECT ‘|| v_markets_list || ‘
from QUOTE_DATA qm
where QM.SYMBOL in ‘’’ || P_SYMBOL || ‘’’;
— Fetch all the market sequence for timeframe.
OPEN cur_qm_seq_ref FOR v_work_markets;
FETCH cur_qm_seq_ref INTO v_market_seq_list;
CLOSE cur_qm_seq_ref;
Execute this query to return the comma delimited values to retrieve correct records to filter and returned.
Here’s the code snipped to retrieve the quote center code rows using the dynamic query.
v_qm_market :=
‘(SELECT quote_center_code
from QUOTE_DATA qm
where QM.QUOTE_SEQ in ( ‘|| v_MARKET_SEQ_LISTS ||’)’;
Conclusion:
In summary is that LISTAGG is here to stay and is documented and support by Oracle. Other option were more workarounds and not recommended for future use. I have found the LISTAGG to be a good string aggregation technique that all developers to be aware of for the right situation. Clearly the performance is faster for the new LISTAGG function over previous techniques used before.