Oracle SQL – Converting multiple rows into single row

One of the project I’m working on has a requirement where if an employee has multiple assignments (multiple rows in the assignment table), then the SQL should consolidate his assignments into one row, with each column holding multiple values (for each row) with a delimiter.

For eg: Here is a sample table

SQL> desc test_asg
Assignment_id number(15)
Title varchar2(50)  — Job title
Emp_cat varchar2(2)  — Employment category

Here is the data in the table:

ASSIGNMENT_ID    TITLE         EMP_CAT
100              Comp info     AP
100              Technician    AP
101              Faculty       AP
102              Teaching      CS
102              Grad Assist   CS
102              Secretary     AP
103              Director      AP

The output requirement is

ASSIGNMENT_ID    JOB_TITLE                         EMP_CATEGORY
100              Comp info;Technician              AP;AP
101              Faculty                           AP
102              Teaching;Grad Assist;Secretary    CS;CS;AP
103              Director                          AP

Here is the SQL I wrote to get the output.

select assignment_id, substr(asg_title,2) JOB_TITLE, substr(asg_empcat,2) EMP_CATEGORY
from (
select assignment_id, max(sys_connect_by_path(title,’;')) asg_title, max(sys_connect_by_path(emp_cat,’;')) asg_empcat
from (
select assignment_id, title, emp_cat, row_number() over (partition by assignment_id order by assignment_id) rnum
from test_asg
)
start with rnum = 1
connect by prior rnum = rnum-1 and prior assignment_id = assignment_id
group by assignment_id
order by assignment_id
)
order by assignment_id;

The SYS_CONNECT_BY_PATH function returns the list of titles concatenated together and list of emp_cat connected together for each assignment id. The Start with .. Connect by clause is used to select data having hierarchical relationship.

Technorati Tags: , , , , ,

This entry was posted in Oracle, Technology and tagged , , , , , . Bookmark the permalink.

15 Responses to Oracle SQL – Converting multiple rows into single row

  1. dr says:

    Thank you. You saved me a lot of time. I had such a headache over this.

  2. Ryan says:

    Wanted to offer my thanks as well. Helped me figure out a query I was working on that concatenates EmployeeIDs of a person’s direct-reports into a single field.

  3. Arun says:

    Ade,

    I’m stuck with a big project now, so I’m not sure how much time I would be able to spend to help you. If you need immediate help, try Oracle SQL forum at http://forums.oracle.com/forums/forum.jspa?forumID=75 . I’m sorry I couldn’t help a lot.

  4. Ade says:

    Hello Arun,

    wondered if you could help?

    I have this string
    Expense_Inv_8- ExpenseInv_7- Exp001- Expense_Inv_6- Expense_Inv_5- Expense_Inv_4- Expense_Inv_3- Expense_Inv_2- Expense_inv1

    and I need to display them in sections as explained below

    Section 1 Section 2 section 3 section 4
    Expense_Inv_8- ExpenseInv_7- Exp001;Expense_Inv_6- Expense_Inv_5;Expense_Inv_4- Expense_Inv_3;Expense_Inv_2;

    need to split this string into 4 section seperated by ‘;’ and each section should be no more that 35 chracters, if null should end ;;;

    Section 1 35 Character ended by;
    section 2, broken off after Expense_Inv_5 because Expense_Inv_4 will take it over 35 chracters)

    regards
    Ade

  5. Ade says:

    Hi Arun,

    Just wanted to say thanks for this information.
    It really helped me in a query I was writting.

    God bless

    Thanks
    Ade

  6. Arun says:

    Try checking explain plan and see if it can be tuned further. I think 30 secs is reasonable for 60,000 records, but i can’t say 100% sure since I don’t know the SQL and table layout and requirements. Since you have nested SQL statements, check one by one.

    • D Jagadesan says:

      Thank you for the immediate reply Arun!

      Here is my requirement,
      TABLE: CUSTOMER_INPUT_FIELD
      COLUMNS: RECORD_KEY RECORD_ID FIELD_ID FIELD_VALUE
      DATA:
      A001 NAME SATHISH
      A001 DEPT ACCOUNTS
      A001 DESG ACCOUNTANT
      A002 NAME RAJESH
      A002 DEPT HR
      A003 DESG RECRUIT

      I need to display it as
      A001 NAME,DEPT,DESG SATHISH,ACCOUNTS,ACCOUNTANT
      A002 NAME,DEPT,DESG RAJESH,HR,RECRUIT

      With the help of ur query, I prepared a query for the same,

      select RECORD_ID, substr(asg_fieldid,2) FIELD_ID, substr(asg_fieldvalue,2) FIELD_VALUE from ( select RECORD_ID, max(sys_connect_by_path(FIELD_VALUE,’;')) asg_fieldvalue, max(sys_connect_by_path(FIELD_ID,’;')) asg_fieldid from (select RECORD_ID, FIELD_VALUE, FIELD_ID, row_number() over (partition by RECORD_ID order by RECORD_ID) rnum from CUSTOMER_INPUT_FIELD) start with rnum = 1 connect by prior rnum = rnum-1 and prior RECORD_ID = RECORD_ID group by RECORD_ID order by RECORD_ID) order by RECORD_ID;

      So… I am currently trying minimize the query processing time by setting max results and iterate for next result set.

      Thank You
      Jagadesan

  7. D Jagadesan says:

    Hi,

    This query matched my exact reqiurement… Thank you very much!

    But when i used this query, my sql editor takes an average time of 30 secs to display the result of 60000 records as 10000 records.
    ie… 1 emp id has 6 categories

    Is there any way to reduce the query processing time?

    - Jagadesan

  8. samraj says:

    to convert multiple row to single row notusing pl/sql

    c
    —————–
    A
    B
    C
    D

    output
    c
    —————–
    A, B, C, D

    and

    c
    —————–

    A, B, C, D

    output:
    c
    —————-
    A
    B
    C
    D

  9. Arun says:

    Lotus,

    I would like to help, but there is not much detail in your requirements to help. I’m also in the process of clearing my work backlog. Try http://asktom.oracle.com for solutions.

  10. Lotus says:

    I want the output as
    PRDCT_FUND_INTRST_RATE_ID RNWL_RT_STRT_DT RNWL_RT_END_DT RNWL_RT
    2 5/30/1985 5/30/1987 0.08
    2 5/30/1987 5/30/1990 0.06
    2 5/30/1990 5/30/1992 0.08
    2 5/30/1992 5/30/1993 0.06
    2 5/30/1993 5/30/1996 0.08
    2 5/30/1996 0.01

    Via SQL. No PLSQL code. Please help me to achieve this
    duration roll up.

  11. Lotus says:

    PRDCT_FUND_INTRST_RATE_ID RNWL_RT_STRT_DT RNWL_RT_END_DT RNWL_RT
    2 5/30/1985 5/30/1986 0.08
    2 5/30/1986 5/30/1987 0.08
    2 5/30/1987 5/30/1988 0.06
    2 5/30/1988 5/30/1989 0.06
    2 5/30/1989 5/30/1990 0.06
    2 5/30/1990 5/30/1991 0.08
    2 5/30/1991 5/30/1992 0.08
    2 5/30/1992 5/30/1993 0.06
    2 5/30/1993 5/30/1994 0.08
    2 5/30/1994 5/30/1995 0.08
    2 5/30/1995 5/30/1996 0.08
    2 5/30/1996 0.01

  12. Mir says:

    Thanks a lot, this was very helpful. – Citigroup.

  13. Kamran says:

    Looks very cool.

    How do you fit the concatenated data in the column that has a predefined size. If the original size is 50 and after you concatenate unknown number of assignments them it becomes 55 – would you not get a sql error for size? Would you make your column an unreasonably large all the time in case you have to concatenate?

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*


You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>