我正在使用Oracle 11g r2,我需要从多行连接字符串(VARCHAR2,300)。我使用的LISTAGG
效果很好,直到连接的字符串达到限制。那时我收到ORA-01489: result of string concatenation is too long
。
最后,我只想要连接字符串的前4000个字符。我如何到达并不重要。我会接受效率低下的解决方案。
这是我的疑问:
SELECT LISTAGG(T.NAME, ' ') WITHIN GROUP (ORDER BY NULL)
FROM T
答案 0 :(得分:4)
此代码适用于任何长度的数据,足够快
SELECT REPLACE(
REPLACE(
XMLAGG(
XMLELEMENT("A",T.NAME)
ORDER BY 1).getClobVal(),
'<A>',''),
'</A>','[delimiter]')
FROM T
答案 1 :(得分:3)
您可以使用内置(但已弃用)的STRAGG功能
select sys.stragg(distinct name) from t
(请注意,似乎有必要避免重复)
或定义您自己的聚合函数/类型:
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;
并像这样使用它:
select STRAGG(name) from t
我相信这种方法是由汤姆·凯特(Tom Kyte)提出的(至少,我从那里得到了它 - Asktom: StringAgg
答案 2 :(得分:1)
也许它会对你有所帮助:
substr(string, 1, 4000)
编辑:
或尝试
SELECT [column], rtrim(
xmlserialize(content
extract(
xmlagg(xmlelement("n", (T.NAME||',') order by [column])
, '//text()'
)
)
, ','
) as list
FROM [table]
GROUP BY [column]
;
答案 3 :(得分:1)
这是LISTAGG函数的缺点,它不处理由于LISTAGG分析函数而生成的字符串的限制。为此,您需要获取长度的累积和,并根据您需要限制。
worked out example on emp table
select listagg(ename,' ')within group (order by null)
from
(
select ename,
sum( length( ename ) + 1)
over ( order by ename rows between unbounded preceding and current row) length
from emp
)where lngth <= 4000
;
但是这不会给出完美的结果,因为如果查看内部查询,它将生成一个带有ename的列,其长度如下所示
ename lenght
===================
gaurav 6
rohan 11
:
:
garima 3996
anshoo 4002
=====================
所以上面的函数会给你结果直到garima
....直到ansh
,因为listagg是基于内部查询的长度列。