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
Description The LISTAGG aggregate function now supports duplicate elimination by using the new DISTINCT keyword.
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.
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.
Listagg() returns a varchar2. This is limited to 4,000 bytes (32,767 if you're using extended data types).
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With