Home » SQL & PL/SQL » SQL & PL/SQL » Clob_Agg Order by (Oracle 11g, XP)
Clob_Agg Order by [message #597054] Mon, 30 September 2013 11:21 Go to next message
rajivn786
Messages: 161
Registered: January 2010
Senior Member
Hi,

I am having an issue with clob_agg...ordered by a field.


with test_asg as (
                  select 100 ASSIGNMENT_ID, 'Comp info' TITLE, 'AP' EMP_CAT from dual union all
                  select  100,'Technician','AP'  from dual union all
                  select  101,'Faculty','AP'  from dual union all
                  select  102,'Teaching','CS'  from dual union all
                  select  102,'Grad Assist','CS'  from dual union all
                  select  102,'Secretary','AP'  from dual union all
                  select  103,'Director','AP'  from dual
                 )
select  ASSIGNMENT_ID,
        RTRIM(CLOBAGG(TITLE || ';'),';') TITLE,
        RTRIM(CLOBAGG(EMP_CAT || ';'),';') EMP_CAT
  from  test_asg
  group by ASSIGNMENT_ID
  order by ASSIGNMENT_ID


Here I need clob concatenation based on ordered assignment name...

op should be based on title in alphabetical order(1st character)..

For 102 it should be 
Grad Assist, Secretary, Teaching

G,S,T -- Alphabetical order


Code I tried : (didn't keep the data in the order)
with test_asg as (
                  select 100 ASSIGNMENT_ID, 'Comp info' TITLE, 'AP' EMP_CAT from dual union all
                  select  100,'Technician','AP'  from dual union all
                  select  101,'Faculty','AP'  from dual union all
                  select  102,'Teaching','CS'  from dual union all
                  select  102,'Grad Assist','CS'  from dual union all
                  select  102,'Secretary','AP'  from dual union all
                  select  103,'Director','AP'  from dual
                 )
select  ASSIGNMENT_ID,
        RTRIM(clipmerge_dm.CLOBAGG(TITLE || ';'),';') TITLE,
        RTRIM(clipmerge_dm.CLOBAGG(EMP_CAT || ';'),';') EMP_CAT
  from (Select * from test_asg order by assignment_id, title)
  group by ASSIGNMENT_ID
  order by ASSIGNMENT_ID



Clobagg function :

create or replace
  type clobagg_type as object(
                              text clob,
                              static function ODCIAggregateInitialize(
                                                                      sctx in out clobagg_type
                                                                     )
                                return number,
                              member function ODCIAggregateIterate(
                                                                   self  in out clobagg_type,
                                                                   value in     clob
                                                                  )
                                return number,
                              member function ODCIAggregateTerminate(
                                                                     self        in  clobagg_type,
                                                                     returnvalue out clob,
                                                                     flags in number
                                                                    )
                                return number,
                              member function ODCIAggregateMerge(
                                                                 self in out clobagg_type,
                                                                 ctx2 in     clobagg_type
                                                                )
                                return number
                             );
/ 
create or replace
  type body clobagg_type
    is
      static function ODCIAggregateInitialize(
                                              sctx in out clobagg_type
                                             )
        return number
        is
        begin
            sctx := clobagg_type(null) ;
            return ODCIConst.Success ;
      end;
      member function ODCIAggregateIterate(
                                           self  in out clobagg_type,
                                           value in     clob
                                          )
        return number
        is
        begin
            self.text := self.text || value ;
            return ODCIConst.Success;
      end;
      member function ODCIAggregateTerminate(
                                             self        in  clobagg_type,
                                             returnvalue out clob,
                                             flags       in  number
                                            )
        return number
        is
        begin
            returnValue := self.text;
            return ODCIConst.Success;
        end;
      member function ODCIAggregateMerge(
                                         self in out clobagg_type ,
                                         ctx2 in     clobagg_type
                                        )
        return number
        is
        begin
            self.text := self.text || ctx2.text;
            return ODCIConst.Success;
        end;
end;
/ 
create or replace
  function clobagg(
                   input clob
                  )
    return clob
    deterministic
    parallel_enable
    aggregate using clobagg_type;
/ 


Thanks.


[Updated on: Mon, 30 September 2013 11:22]

Report message to a moderator

icon2.gif  Re: Clob_Agg Order by [message #597059 is a reply to message #597054] Mon, 30 September 2013 12:04 Go to previous messageGo to next message
Michel Cadot
Messages: 68765
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

If you want an order you have to store the values in an array then sort the values and concatenate them in ODCIAggregateTerminate function.

Re: Clob_Agg Order by [message #597062 is a reply to message #597059] Mon, 30 September 2013 12:27 Go to previous messageGo to next message
rajivn786
Messages: 161
Registered: January 2010
Senior Member
Thanks Mike..I wrote PLSQL code to do this rather than using the function..
This code is not related to the example..but I hope it serves the purpose..
create or replace procedure prc_prog_notes
 as
  V_NOTE_ID VARCHAR2(1000);
  V_NOTE_DATE DATE;
  V_NOTE_STATUS VARCHAR2(1000);
  V_NOTE_EDITOR_ID  VARCHAR2(1000);
  V_NOTES CLOB;
  V_ENTERED_BY VARCHAR2(1000);
  V_ENCOUNTER_ID VARCHAR2(1000);

  CURSOR C_ALL_ENCOUNTERS IS
SELECT DISTINCT NOTE_ID,
                NOTE_DATE,
                NOTE_STATUS,
                ENTERED_BY,
                NOTE_EDITOR_ID,
                ENCOUNTER_ID
  FROM CM_PROGRESS_NOTES
/* WHERE ENCOUNTER_ID = 16*/;

  CURSOR C_NOTES (P_ENC_ID VARCHAR2, P_NOTE_ID VARCHAR2) IS
   SELECT
         CP.ENCOUNTER_ID,
         CP.NOTE_ID,
         CP.NOTE_TEXT
     FROM CM_PROGRESS_NOTES CP
     WHERE CP.ENCOUNTER_ID = P_ENC_ID
      AND  CP.NOTE_ID      = P_NOTE_ID
     -- AND NOTE_ID = 18142669
     -- AND  ENCOUNTER_ID = 16
      ORDER BY NOTE_ID, ENCOUNTER_ID, LINE;

   TYPE V_TT IS TABLE OF C_NOTES%ROWTYPE INDEX BY PLS_INTEGER;
   L_TT V_TT;

BEGIN
-- DBMS_OUTPUT.put_line('BEFORE LOOP');
  FOR L1 IN C_ALL_ENCOUNTERS
   LOOP
     V_ENCOUNTER_ID             := L1.ENCOUNTER_ID;
     V_NOTE_ID                  := L1.NOTE_ID;
     V_NOTE_DATE                := L1.NOTE_DATE;
     V_NOTE_STATUS              := L1.NOTE_STATUS;
     V_NOTE_EDITOR_ID           := L1.NOTE_EDITOR_ID;
     V_ENTERED_BY               := L1.ENTERED_BY;

   OPEN C_NOTES(L1.ENCOUNTER_ID,L1.NOTE_ID);
     V_NOTES := '';


    LOOP
      FETCH C_NOTES BULK COLLECT INTO L_TT LIMIT 7500;
       FOR indx IN 1 .. L_TT.COUNT
        LOOP
          V_NOTES := V_NOTES || L_TT(indx).NOTE_TEXT;
        END LOOP;
      EXIT WHEN L_TT.COUNT = 0;
    END LOOP;

 CLOSE C_NOTES;

    INSERT /*+ append */
     INTO PROGRESS_NOTES VALUES (V_ENCOUNTER_ID,V_NOTE_ID,V_NOTE_DATE,V_NOTE_STATUS,
                                              V_NOTE_EDITOR_ID,V_ENTERED_BY,V_NOTES);
     COMMIT;

  End Loop;
END;


icon4.gif  Re: Clob_Agg Order by [message #597065 is a reply to message #597062] Mon, 30 September 2013 12:48 Go to previous messageGo to next message
Michel Cadot
Messages: 68765
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

I didn't analyse the code but it is useless to use APPEND hint on an INSERT VALUES.
In addition, it is a bad habit to commit inside a procedure; are you sure the one which calls it wants you commit his modifications?

Re: Clob_Agg Order by [message #597067 is a reply to message #597065] Mon, 30 September 2013 13:08 Go to previous messageGo to next message
rajivn786
Messages: 161
Registered: January 2010
Senior Member
Do you mean commit outside the loop ...
Also, what would be the approach if you dont want to use commit inside a proc?
icon3.gif  Re: Clob_Agg Order by [message #597070 is a reply to message #597067] Mon, 30 September 2013 13:37 Go to previous messageGo to next message
Michel Cadot
Messages: 68765
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator
Quote:
Do you mean commit outside the loop ...


No, I meant commit outside the procedure.

Quote:
Also, what would be the approach if you dont want to use commit inside a proc?


The one I mentioned in my first post.

[Updated on: Mon, 30 September 2013 13:37]

Report message to a moderator

Re: Clob_Agg Order by [message #597173 is a reply to message #597070] Tue, 01 October 2013 08:00 Go to previous messageGo to next message
ilikesql
Messages: 3
Registered: October 2013
Location: pune
Junior Member
Try this

with test_asg as (
select 100 ASSIGNMENT_ID, 'Comp info' TITLE, 'AP' EMP_CAT from dual union all
select 100,'Technician','AP' from dual union all
select 101,'Faculty','AP' from dual union all
select 102,'Teaching','CS' from dual union all
select 102,'Grad Assist','CS' from dual union all
select 102,'Secretary','AP' from dual union all
select 103,'Director','AP' from dual
),
test_order_by as (select * from test_asg order by assignment_id,title asc)
select ASSIGNMENT_ID,
RTRIM(wm_concat(TITLE || ';'),';') TITLE,
RTRIM(wm_concat(EMP_CAT || ';'),';') EMP_CAT
from test_order_by
group by ASSIGNMENT_ID
order by ASSIGNMENT_ID
icon4.gif  Re: Clob_Agg Order by [message #597179 is a reply to message #597173] Tue, 01 October 2013 08:13 Go to previous messageGo to next message
Michel Cadot
Messages: 68765
Registered: March 2007
Location: Saint-Maur, France, https...
Senior Member
Account Moderator

Do not use WM_CONCAT, it is for Oracle only, it is not documented and so not supported.
In addition, it requires some options are installed.

Re: Clob_Agg Order by [message #597235 is a reply to message #597054] Tue, 01 October 2013 19:56 Go to previous message
Solomon Yakobson
Messages: 3305
Registered: January 2010
Location: Connecticut, USA
Senior Member
rajivn786 wrote on Mon, 30 September 2013 12:21
Here I need clob concatenation based on ordered assignment name...


It is not clear why you are using CLOB_AGG. If TITLE and EMP_CAT are VARCHAR2s but concatenation result can exceed 4000 bytes, use XMLAGG:

with test_asg as (
                  select 100 ASSIGNMENT_ID, 'Comp info' TITLE, 'AP' EMP_CAT from dual union all
                  select  100,'Technician','AP'  from dual union all
                  select  101,'Faculty','AP'  from dual union all
                  select  102,'Teaching','CS'  from dual union all
                  select  102,'Grad Assist','CS'  from dual union all
                  select  102,'Secretary','AP'  from dual union all
                  select  103,'Director','AP'  from dual
                 )
select  ASSIGNMENT_ID,
        RTRIM(XMLAGG(XMLELEMENT(e,TITLE,';').EXTRACT('//text()') ORDER BY TITLE).GETCLOBVAL(),';') TITLE,
        RTRIM(XMLAGG(XMLELEMENT(e,EMP_CAT,';').EXTRACT('//text()') ORDER BY TITLE).GETCLOBVAL(),';') EMP_CAT
  from  test_asg
  group by ASSIGNMENT_ID
  order by ASSIGNMENT_ID
/

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

SQL>


If TITLE/EMP_CAT is CLOB you have another issue - order by is not supported for CLOBs:

with test_asg as (
                  select 100 ASSIGNMENT_ID, to_clob('Comp info') TITLE, to_clob('AP') EMP_CAT from dual union all
                  select  100,to_clob('Technician'), to_clob('AP')  from dual union all
                  select  101,to_clob('Faculty'), to_clob('AP')  from dual union all
                  select  102,to_clob('Teaching'), to_clob('CS')  from dual union all
                  select  102,to_clob('Grad Assist'), to_clob('CS')  from dual union all
                  select  102,to_clob('Secretary'), to_clob('AP')  from dual union all
                  select  103,to_clob('Director'), to_clob('AP')  from dual
                 )
select  ASSIGNMENT_ID,
        RTRIM(XMLAGG(XMLELEMENT(e,TITLE,';').EXTRACT('//text()') ORDER BY TITLE).GETCLOBVAL(),';') TITLE,
        RTRIM(XMLAGG(XMLELEMENT(e,EMP_CAT,';').EXTRACT('//text()') ORDER BY EMP_CAT).GETCLOBVAL(),';') EMP_CAT
  from  test_asg
  group by ASSIGNMENT_ID
  order by ASSIGNMENT_ID
/
        RTRIM(XMLAGG(XMLELEMENT(e,EMP_CAT,';').EXTRACT('//text()') ORDER BY EMP_CAT).GETCLOBVAL(),';') EMP_CAT
                                                                            *
ERROR at line 12:
ORA-00932: inconsistent datatypes: expected - got CLOB


SQL>


One possible solution is object type with ORDER method which will allow sorting CLOBS:

CREATE OR REPLACE
  TYPE clob_obj IS OBJECT(
                          c CLOB,
                          ORDER MEMBER FUNCTION equals(
                                                       p_c clob_obj
                                                      )
                            RETURN NUMBER 
                         )
/
CREATE OR REPLACE
  TYPE BODY clob_obj
    IS
      ORDER MEMBER FUNCTION equals(
                                   p_c clob_obj
                                  )
        RETURN NUMBER
        IS
        BEGIN
            RETURN dbms_lob.compare(SELF.c,p_c.c);
      END;
END;
/


Now:

with test_asg as (
                  select 100 ASSIGNMENT_ID, 'Comp info' TITLE, 'AP' EMP_CAT from dual union all
                  select  100,'Technician','AP'  from dual union all
                  select  101,'Faculty','AP'  from dual union all
                  select  102,'Teaching','CS'  from dual union all
                  select  102,'Grad Assist','CS'  from dual union all
                  select  102,'Secretary','AP'  from dual union all
                  select  103,'Director','AP'  from dual
                 ),
            t as (
                  select  ASSIGNMENT_ID,
                          clob_obj(TITLE) TITLE,
                          clob_obj(EMP_CAT) EMP_CAT
                    from  test_asg
                 )
select  ASSIGNMENT_ID,
        RTRIM(XMLAGG(XMLELEMENT(e,TITLE,';').EXTRACT('//text()') ORDER BY TITLE).GETCLOBVAL(),';') TITLE,
        RTRIM(XMLAGG(XMLELEMENT(e,EMP_CAT,';').EXTRACT('//text()') ORDER BY EMP_CAT).GETCLOBVAL(),';') EMP_CAT
  from  t
  group by ASSIGNMENT_ID
  order by ASSIGNMENT_ID
/

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

SQL>


SY.

[Updated on: Tue, 01 October 2013 19:58]

Report message to a moderator

Previous Topic: PL/SQL for 3 different tables
Next Topic: CHARSET CONVERSION
Goto Forum:
  


Current Time: Mon Aug 04 10:34:13 CDT 2025