Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

truncated LISTAGG string [duplicate]

I'm using Oracle 11g r2 and I need to concatenate strings (VARCHAR2, 300) from multiple rows. I'm using LISTAGG which works great until the concatenated string reaches the limit. At that point I receive a ORA-01489: result of string concatenation is too long.

In the end, I only want the first 4000 chars of the concatenated string. How I get there doesn't matter. I will accept inefficient solutions.

Here's my query:

SELECT LISTAGG(T.NAME, ' ') WITHIN GROUP (ORDER BY NULL)
FROM T
like image 592
Howie Avatar asked Sep 07 '12 09:09

Howie


People also ask

Does Listagg remove duplicates?

Description The LISTAGG aggregate function now supports duplicate elimination by using the new DISTINCT keyword.

What can be used instead of Listagg?

Alternative to LISTAGG Function is to create a user Function our self and here is what the Function looks like. Using the Function (ge_employee_names) in Select to generate LISTAGG result. SELECT DISTINCT deptno, get_employee_names(deptno) FROM baniya.

Can I use distinct with Listagg?

With the DISTINCT option, the processing to remove duplicate values can be done directly within the LISTAGG function. The result is simpler, faster, more efficient SQL.

What is the limit for Listagg?

Listagg() returns a varchar2. This is limited to 4,000 bytes (32,767 if you're using extended data types).


2 Answers

This code works for any length of data, fast enough

SELECT REPLACE(
         REPLACE(
           XMLAGG(
             XMLELEMENT("A",T.NAME)
           ORDER BY 1).getClobVal(),
         '<A>',''),
       '</A>','[delimiter]')
FROM T
like image 61
Gregory Kneller Avatar answered Oct 01 '22 01:10

Gregory Kneller


You can either use the built-in (but deprecated) STRAGG function

    select sys.stragg(distinct name) from t

(please note that distinct seems to be necessary to avoid duplicates)

or define your own aggregation function / type:

CREATE OR REPLACE TYPE "STRING_AGG_TYPE" as object
(
  total varchar2(4000),

  static function ODCIAggregateInitialize(sctx IN OUT string_agg_type) return number,

  member function ODCIAggregateIterate(self  IN OUT string_agg_type,
                                       value IN varchar2) return number,

  member function ODCIAggregateTerminate(self        IN string_agg_type,
                                         returnValue OUT varchar2,
                                         flags       IN number) return number,

  member function ODCIAggregateMerge(self IN OUT string_agg_type,
                                     ctx2 IN string_agg_type) return number
);

CREATE OR REPLACE TYPE BODY "STRING_AGG_TYPE" is

  static function ODCIAggregateInitialize(sctx IN OUT string_agg_type) return number is
  begin
    sctx := string_agg_type(null);
    return ODCIConst.Success;
  end;

  member function ODCIAggregateIterate(self  IN OUT string_agg_type,
                                       value IN varchar2) return number is
  begin
    -- prevent buffer overflow for more than 4,000 characters
    if nvl(length(self.total),
           0) + nvl(length(value),
                    0) < 4000 then
      self.total := self.total || ';' || value;
    end if;
    return ODCIConst.Success;
  end;

  member function ODCIAggregateTerminate(self        IN string_agg_type,
                                         returnValue OUT varchar2,
                                         flags       IN number) return number is
  begin
    returnValue := ltrim(self.total,
                         ';');
    return ODCIConst.Success;
  end;

  member function ODCIAggregateMerge(self IN OUT string_agg_type,
                                     ctx2 IN string_agg_type) return number is
  begin
    self.total := self.total || ctx2.total;
    return ODCIConst.Success;
  end;

end;

CREATE OR REPLACE FUNCTION stragg(input varchar2 )
   RETURN varchar2
   PARALLEL_ENABLE AGGREGATE USING string_agg_type;

and use it like this:

select STRAGG(name) from t

I believe this approach was orginally proposed by Tom Kyte (at least, that's where I got it from - Asktom: StringAgg

like image 24
Frank Schmitt Avatar answered Oct 01 '22 01:10

Frank Schmitt