Saturday, October 21, 2017

String Aggregation In Oracle

To aggregate data from a number of rows into a single row where giving a list of data associated with a specific value.

For example if you want to select a list of employees for each department we have the following methods to achieve the result.
say EMP table of SCOTT schema contains the following data.

DEPTNO ENAME
---------- ----------
        20 SMITH
        30 ALLEN
        30 WARD
        20 JONES
        30 MARTIN
        30 BLAKE
        10 CLARK
        20 SCOTT
        10 KING
        30 TURNER
        20 ADAMS
        30 JAMES
        20 FORD
        10 MILLER
and we want to achieve the result as following:
DEPTNO EMPLOYEES
---------- ------------------------------------------------
        10 CLARK,KING,MILLER
        20 SMITH,FORD,ADAMS,SCOTT,JONES
        30 ALLEN,BLAKE,MARTIN,TURNER,JAMES,WARD
by using the following methods we can achieve the above result. 
this is called string aggregation. 

1. Using LISTAGG analytic function.
2. Using WM_CONCAT built-in function
3. By using COLLECT function
4. using ROW_NUMBER and SYS_CONNECT_BY_PATH functions.

LISTAGG:
i. it was introduced in oracle 11g release 2.
ii. by using this function we can aggregate strings very easily.
iii. it provides the advantage of ordering the elements in the concatenated list.

eg:


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,SCOTT,SMITH
        30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
WM_CONCAT:
SELECT deptno, wm_concat(ename) AS employees
FROM   emp
GROUP BY deptno;

    DEPTNO EMPLOYEES
---------- ------------------------------------------------
        10 CLARK,KING,MILLER
        20 SMITH,FORD,ADAMS,SCOTT,JONES
        30 ALLEN,BLAKE,MARTIN,TURNER,JAMES,WARD
COLLECT:
the collect function works from oracle 10g. in order to achieve the above same result by using COLLECT function we need a table type and a function to convert the contents of the table type to a string. 
follow the steps:
1. first create a table type
CREATE OR REPLACE  TYPE T_VAR2_TAB  AS TABLE OF VARCHAR2(4000);
/
2. create a function to convert the contents of the table type to string.
CREATE OR REPLACE FUNCTION tab_to_string (p_varchar2_tab  IN  t_var2_tab,
                                          p_delimiter     IN  VARCHAR2 DEFAULT ',') RETURN VARCHAR2 IS
  l_string     VARCHAR2(32767);
BEGIN
  FOR i IN p_varchar2_tab.FIRST .. p_varchar2_tab.LAST LOOP
    IF i != p_varchar2_tab.FIRST THEN
      l_string := l_string || p_delimiter;
    END IF;
    l_string := l_string || p_varchar2_tab(i);
  END LOOP;
  RETURN l_string;
END tab_to_string;
/
then query the function with the COLLECT function
SELECT deptno,
       tab_to_string(CAST(COLLECT(ename) AS t_var2_tab)) AS employees
FROM   emp
GROUP BY deptno;
       
    DEPTNO EMPLOYEES
---------- ------------------------------------------------
        10 CLARK,KING,MILLER
        20 SMITH,JONES,SCOTT,ADAMS,FORD
        30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
        

4. ROW_NUMBER() and SYS_CONNECT_BY_PATH functions in Oracle 9i

the ROW_NUMBER() and SYS_CONNECT_BY_PATH functions to achieve the same result without the use of PL/SQL or additional type definitions.
SELECT deptno,
       LTRIM(MAX(SYS_CONNECT_BY_PATH(ename,','))
       KEEP (DENSE_RANK LAST ORDER BY curr),',') AS employees
FROM   (SELECT deptno,
               ename,
               ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) AS curr,
               ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY ename) -1 AS prev
        FROM   emp)
GROUP BY deptno
CONNECT BY prev = PRIOR curr AND deptno = PRIOR deptno
START WITH curr = 1;

    DEPTNO EMPLOYEES
---------- ------------------------------------------------
       10 CLARK,KING,MILLER
       20 ADAMS,FORD,JONES,SCOTT,SMITH
       30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD


No comments:

Post a Comment

SupplierAddressImportTemplate.xlsm South Africa Suburb Field mapping in POZ_SUPPLIER_ADDRESSES_INT

Suburb mpping in Supplier Address Import Template will be mapped to Address Element Attribute2 (HZ_LOCATIONS. ADDR_ELEMENT_ATTRIBUTE2)