LISTAGG 함수: "문자열 연결 결과가 너무 깁니다."
Oracle SQL 3.0.04입니다.는 이 하려고 했습니다.LISTAGG
데이터를 그룹화합니다.
CREATE TABLE FINAL_LOG AS
SELECT SESSION_DT, C_IP, CS_USER_AGENT,
listagg(WEB_LINK, ' ')
WITHIN GROUP(ORDER BY C_IP, CS_USER_AGENT) "WEB_LINKS"
FROM webviews
GROUP BY C_IP, CS_USER_AGENT, SESSION_DT
ORDER BY SESSION_DT
하지만 계속 오류가 발생하고 있습니다.
SQL Error: ORA-01489: result of string concatenation is too long
WEB_이기 때문에 출력이 4000을 넘을 수 있습니다.여기서 설명하는 LINK은 url 스템과 url 쿼리의 연결값입니다.
다른 방법이 있나요? 아니면 다른 방법이 있나요?
XMLAGG 함수에서도 같은 기능을 실행할 수 있습니다.
SELECT RTRIM(XMLAGG(XMLELEMENT(E,colname,',').EXTRACT('//text()') ORDER BY colname).GetClobVal(),',') AS LIST
FROM tablename;
그러면 clob 값이 반환되므로 행에 제한이 없습니다.
수 4000바이트는 수 .LISTAGG
기능.잠재적으로 사용자 정의 집계 함수를 생성하여CLOB
가 a a VARCHAR2
. 를CLOB
첫 번째 토론에서 팀이 링크한 원래 askTom 토론에서.
listagg
ISO SQL ( SQL : 2016 ) 。그 일환으로, 그것은 또한on overflow
절은 Oracle clause Oracle 12cR2에서 지원됩니다.
LISTAGG(<expression>, <separator> ON OVERFLOW …)
on overflow
은 '일부러'를 합니다.truncate
(「」) )on overflow error
★★★★★★★★★★★★★★★★★★」
ON OVERFLOW TRUNCATE [<filler>] WITH[OUT] COUNT
옵션에서는 기본적으로 3개의 마침표(...)가 설정되어 있으며, 잘라낸 경우 마지막 요소로 추가됩니다.
count가 지정되어 있고 절단이 발생했을 경우 생략된 값의 수는 괄호로 둘러싸여 결과에 추가됩니다.
★★★의 상세listagg
의 »on overflow
조항: http://modern-sql.com/feature/listagg
은 12cR2 입니다.ON OVERFLOW
의 절LISTAGG
과 같습니다
SELECT pid, LISTAGG(Desc, ' ' ON OVERFLOW TRUNCATE ) WITHIN GROUP (ORDER BY seq) AS desc
FROM B GROUP BY pid;
되지만 4000자, 4000자, 4000자, 4000자 등은 슬로우 .ORA-01489
입니다.ON OVERFLOW
§:
ON OVERFLOW TRUNCATE 'Contd..'
라고 표시됩니다.'Contd..'
은 " " " " 입니다....
)ON OVERFLOW TRUNCATE ''
: 4000달러ON OVERFLOW TRUNCATE WITH COUNT
: 에 총 종료문자뒤에끝에총문자수가표시됩니다.- ' - '...(5512)
ON OVERFLOW ERROR
: 이 the the 가 예상되는LISTAGG
ORA-01489
입니다).error( 「 「 」 「 。
에 적용되는 SQL 제한 4000바이트를 초과했습니다.LISTAGG
뿐만 아니라.
SQL> SELECT listagg(text, ',') WITHIN GROUP (
2 ORDER BY NULL)
3 FROM
4 (SELECT to_char(to_date(level,'j'), 'jsp') text FROM dual CONNECT BY LEVEL < 250
5 )
6 /
SELECT listagg(text, ',') WITHIN GROUP (
*
ERROR at line 1:
ORA-01489: result of string concatenation is too long
회피책으로 XMLAGG를 사용할 수 있습니다.
예를들면,
SQL> SET LONG 2000000
SQL> SET pagesize 50000
SQL> SELECT rtrim(xmlagg(XMLELEMENT(e,text,',').EXTRACT('//text()')
2 ).GetClobVal(),',') very_long_text
3 FROM
4 (SELECT to_char(to_date(level,'j'), 'jsp') text FROM dual CONNECT BY LEVEL < 250
5 )
6 /
VERY_LONG_TEXT
--------------------------------------------------------------------------------
one,two,three,four,five,six,seven,eight,nine,ten,eleven,twelve,thirteen,fourteen
,fifteen,sixteen,seventeen,eighteen,nineteen,twenty,twenty-one,twenty-two,twenty
-three,twenty-four,twenty-five,twenty-six,twenty-seven,twenty-eight,twenty-nine,
thirty,thirty-one,thirty-two,thirty-three,thirty-four,thirty-five,thirty-six,thi
rty-seven,thirty-eight,thirty-nine,forty,forty-one,forty-two,forty-three,forty-f
our,forty-five,forty-six,forty-seven,forty-eight,forty-nine,fifty,fifty-one,fift
y-two,fifty-three,fifty-four,fifty-five,fifty-six,fifty-seven,fifty-eight,fifty-
nine,sixty,sixty-one,sixty-two,sixty-three,sixty-four,sixty-five,sixty-six,sixty
-seven,sixty-eight,sixty-nine,seventy,seventy-one,seventy-two,seventy-three,seve
nty-four,seventy-five,seventy-six,seventy-seven,seventy-eight,seventy-nine,eight
y,eighty-one,eighty-two,eighty-three,eighty-four,eighty-five,eighty-six,eighty-s
even,eighty-eight,eighty-nine,ninety,ninety-one,ninety-two,ninety-three,ninety-f
our,ninety-five,ninety-six,ninety-seven,ninety-eight,ninety-nine,one hundred,one
hundred one,one hundred two,one hundred three,one hundred four,one hundred five
,one hundred six,one hundred seven,one hundred eight,one hundred nine,one hundre
d ten,one hundred eleven,one hundred twelve,one hundred thirteen,one hundred fou
rteen,one hundred fifteen,one hundred sixteen,one hundred seventeen,one hundred
eighteen,one hundred nineteen,one hundred twenty,one hundred twenty-one,one hund
red twenty-two,one hundred twenty-three,one hundred twenty-four,one hundred twen
ty-five,one hundred twenty-six,one hundred twenty-seven,one hundred twenty-eight
,one hundred twenty-nine,one hundred thirty,one hundred thirty-one,one hundred t
hirty-two,one hundred thirty-three,one hundred thirty-four,one hundred thirty-fi
ve,one hundred thirty-six,one hundred thirty-seven,one hundred thirty-eight,one
hundred thirty-nine,one hundred forty,one hundred forty-one,one hundred forty-tw
o,one hundred forty-three,one hundred forty-four,one hundred forty-five,one hund
red forty-six,one hundred forty-seven,one hundred forty-eight,one hundred forty-
nine,one hundred fifty,one hundred fifty-one,one hundred fifty-two,one hundred f
ifty-three,one hundred fifty-four,one hundred fifty-five,one hundred fifty-six,o
ne hundred fifty-seven,one hundred fifty-eight,one hundred fifty-nine,one hundre
d sixty,one hundred sixty-one,one hundred sixty-two,one hundred sixty-three,one
hundred sixty-four,one hundred sixty-five,one hundred sixty-six,one hundred sixt
y-seven,one hundred sixty-eight,one hundred sixty-nine,one hundred seventy,one h
undred seventy-one,one hundred seventy-two,one hundred seventy-three,one hundred
seventy-four,one hundred seventy-five,one hundred seventy-six,one hundred seven
ty-seven,one hundred seventy-eight,one hundred seventy-nine,one hundred eighty,o
ne hundred eighty-one,one hundred eighty-two,one hundred eighty-three,one hundre
d eighty-four,one hundred eighty-five,one hundred eighty-six,one hundred eighty-
seven,one hundred eighty-eight,one hundred eighty-nine,one hundred ninety,one hu
ndred ninety-one,one hundred ninety-two,one hundred ninety-three,one hundred nin
ety-four,one hundred ninety-five,one hundred ninety-six,one hundred ninety-seven
,one hundred ninety-eight,one hundred ninety-nine,two hundred,two hundred one,tw
o hundred two,two hundred three,two hundred four,two hundred five,two hundred si
x,two hundred seven,two hundred eight,two hundred nine,two hundred ten,two hundr
ed eleven,two hundred twelve,two hundred thirteen,two hundred fourteen,two hundr
ed fifteen,two hundred sixteen,two hundred seventeen,two hundred eighteen,two hu
ndred nineteen,two hundred twenty,two hundred twenty-one,two hundred twenty-two,
two hundred twenty-three,two hundred twenty-four,two hundred twenty-five,two hun
dred twenty-six,two hundred twenty-seven,two hundred twenty-eight,two hundred tw
enty-nine,two hundred thirty,two hundred thirty-one,two hundred thirty-two,two h
undred thirty-three,two hundred thirty-four,two hundred thirty-five,two hundred
thirty-six,two hundred thirty-seven,two hundred thirty-eight,two hundred thirty-
nine,two hundred forty,two hundred forty-one,two hundred forty-two,two hundred f
orty-three,two hundred forty-four,two hundred forty-five,two hundred forty-six,t
wo hundred forty-seven,two hundred forty-eight,two hundred forty-nine
4000바이트인 여러 열을 연결하는 경우 각 열의 XMLAGG 출력을 연결하여 SQL 제한 4000바이트를 피할 수 있습니다.
예를들면,
WITH DATA AS
( SELECT 1 id, rpad('a1',4000,'*') col1, rpad('b1',4000,'*') col2 FROM dual
UNION
SELECT 2 id, rpad('a2',4000,'*') col1, rpad('b2',4000,'*') col2 FROM dual
)
SELECT ID,
rtrim(xmlagg(XMLELEMENT(e,col1,',').EXTRACT('//text()') ).GetClobVal(), ',')
||
rtrim(xmlagg(XMLELEMENT(e,col2,',').EXTRACT('//text()') ).GetClobVal(), ',')
AS very_long_text
FROM DATA
GROUP BY ID
ORDER BY ID;
승인된 답변에 추가.비슷한 문제가 발생하여 varchar2가 아닌 clob을 반환하는 사용자 정의 함수를 사용하게 되었습니다.제 해결책은 다음과 같습니다.
CREATE OR REPLACE TYPE temp_data FORCE AS OBJECT
(
temporary_data NVARCHAR2(4000)
)
/
CREATE OR REPLACE TYPE temp_data_table FORCE AS TABLE OF temp_data;
/
CREATE OR REPLACE FUNCTION my_agg_func (p_temp_data_table IN temp_data_table, p_delimiter IN NVARCHAR2)
RETURN CLOB IS
l_string CLOB;
BEGIN
FOR i IN p_temp_data_table.FIRST .. p_temp_data_table.LAST LOOP
IF i != p_temp_data_table.FIRST THEN
l_string := l_string || p_delimiter;
END IF;
l_string := l_string || p_temp_data_table(i).temporary_data;
END LOOP;
RETURN l_string;
END my_agg_func;
/
이제 하는 대신
LISTAGG(column_to_aggregate, '#any_delimiter#') WITHIN GROUP (ORDER BY column_to_order_by)
나는 이걸 해야 한다.
my_agg_func (
cast(
collect(
temp_data(column_to_aggregate)
order by column_to_order_by
) as temp_data_table
),
'#any_delimiter#'
)
필드를 여러 행으로 연결하는 것은 4000자 제한보다 작을 수 있습니다.다음 절차를 따릅니다.
with PRECALC as (select
floor(4000/(max(length(MY_COLUMN)+LENGTH(',')))) as MAX_FIELD_LENGTH
from MY_TABLE)
select LISTAGG(MY_COLUMN,',') WITHIN GROUP(ORDER BY floor(rownum/MAX_FIELD_LENGTH), MY_COLUMN)
from MY_TABLE, PRECALC
group by floor(rownum/MAX_FIELD_LENGTH)
;
LISTAGG에서의 오버플로우 관리
Database 12c SQL 패턴 매칭 함수 MATCH_RECONIZE를 사용하여 제한을 초과하지 않는 값 목록을 반환할 수 있습니다.
코드 예시와 자세한 설명은 아래 링크에 기재되어 있습니다.
https://blogs.oracle.com/datawarehousing/entry/managing_overflows_in_listagg
시나리오에 따라서는 모든 DISIGNT LISTAGG 키를 취득하는 것이 목적이며 LISTAGG가 모든 키를 연결하기 때문에 오버플로가 발생합니다.
여기 작은 예가 있습니다.
create table tab as
select
trunc(rownum/10) x,
'GRP'||to_char(mod(rownum,4)) y,
mod(rownum,10) z
from dual connect by level < 100;
select
x,
LISTAGG(y, '; ') WITHIN GROUP (ORDER BY y) y_lst
from tab
group by x;
X Y_LST
---------- ------------------------------------------------------------------
0 GRP0; GRP0; GRP1; GRP1; GRP1; GRP2; GRP2; GRP3; GRP3
1 GRP0; GRP0; GRP1; GRP1; GRP2; GRP2; GRP2; GRP3; GRP3; GRP3
2 GRP0; GRP0; GRP0; GRP1; GRP1; GRP1; GRP2; GRP2; GRP3; GRP3
3 GRP0; GRP0; GRP1; GRP1; GRP2; GRP2; GRP2; GRP3; GRP3; GRP3
4 GRP0; GRP0; GRP0; GRP1; GRP1; GRP1; GRP2; GRP2; GRP3; GRP3
5 GRP0; GRP0; GRP1; GRP1; GRP2; GRP2; GRP2; GRP3; GRP3; GRP3
6 GRP0; GRP0; GRP0; GRP1; GRP1; GRP1; GRP2; GRP2; GRP3; GRP3
7 GRP0; GRP0; GRP1; GRP1; GRP2; GRP2; GRP2; GRP3; GRP3; GRP3
8 GRP0; GRP0; GRP0; GRP1; GRP1; GRP1; GRP2; GRP2; GRP3; GRP3
9 GRP0; GRP0; GRP1; GRP1; GRP2; GRP2; GRP2; GRP3; GRP3; GRP3
가 허용된 하여 " " "가 됩니다.ORA-01489: result of string concatenation is too long
도 감유 for 는 지원되지 않습니다.LISTAGG( DISTINCT y, '; ')
단, 회피책으로 LISTAGG가 NULL을 무시한다는 사실을 사용할 수 있습니다.ROW_NUMBER를 사용하여 첫 번째 키만 고려합니다.
with rn as (
select x,y,z,
row_number() over (partition by x,y order by y) rn
from tab
)
select
x,
LISTAGG( case when rn = 1 then y end, '; ') WITHIN GROUP (ORDER BY y) y_lst,
sum(z) z
from rn
group by x
order by x;
X Y_LST Z
---------- ---------------------------------- ----------
0 GRP0; GRP1; GRP2; GRP3 45
1 GRP0; GRP1; GRP2; GRP3 45
2 GRP0; GRP1; GRP2; GRP3 45
3 GRP0; GRP1; GRP2; GRP3 45
4 GRP0; GRP1; GRP2; GRP3 45
5 GRP0; GRP1; GRP2; GRP3 45
6 GRP0; GRP1; GRP2; GRP3 45
7 GRP0; GRP1; GRP2; GRP3 45
8 GRP0; GRP1; GRP2; GRP3 45
9 GRP0; GRP1; GRP2; GRP3 45
같은 수 .GROUP BY x,y
브쿼쿼서의 ROW_NUMBER
다른 모든 집계 함수를 다음과 같이 사용할 수 있습니다.SUM(z)
.
조언해 주셔서 감사합니다.할 때 했는데, '우리'도 마찬가지입니다.xmlagg
ORA-01489입니다.그.
- : 내 중: " " " " "
xmlagg
에는 큰텍스트가 됩니다. - : 적용: 적용
to_clob()
★★★★★★ 。
예:
rtrim(xmlagg(xmlelement(t, t.field1 ||'|'||
t.field2 ||'|'||
t.field3 ||'|'||
to_clob(t.field4),'; ').extract('//text()')).GetClobVal(),',')
이게 누구에게도 도움이 됐으면 좋겠다.
Oracle LISTAGG를 사용하여 비슷한 문제를 해결할 수 있었습니다.그룹화 대상 항목이 4K 제한을 초과한 적이 있었지만, 첫 번째 데이터 집합에서 집계할 첫 번째 15개 항목을 가져오도록 하면 이 문제는 쉽게 해결되었습니다. 각 항목에는 256K 제한이 있습니다.
상세 정보:프로젝트에는 변경 순서와 설명이 있습니다.데이터베이스가 256K 제한의 청크로 변경 텍스트를 받도록 설정된 이유는 알려지지 않았지만 설계 제약 조건 중 하나입니다.따라서 표에 변경 설명을 제공하는 응용 프로그램은 254K에서 중지하고 삽입한 후 다음 텍스트 세트를 가져오고 254K를 초과하면 다른 행이 생성됩니다.그래서 우리는 1:1의 변경 순서를 위한 프로젝트를 가지고 있습니다.그럼 이걸 1:n으로 설명을 해드릴게요.LISTAGG는 이 모든 것을 연결합니다.RMRKS_SN 값은 각 주석 및/또는 254K 문자마다 1개씩 있습니다.
가장 큰 RMRKS_SN은 31이므로 첫 번째 데이터셋은 SN 0에서 15, 두 번째 데이터셋은 16에서 30, 마지막 데이터셋은 31에서 45로 풀링했습니다.자, 변경 주문에 대한 많은 설명을 추가할 예정입니다.
SQL 보고서에서 Tablix는 첫 번째 데이터 세트에 연결됩니다.다른 데이터를 얻으려면 다음과 같은 식을 사용합니다.
=최초(필드!NON_STD_TXT.값, "DataSet_EXPLAN" & First(필드!NON_STD_TXT.값, "ds_EXPLAN_SN_16"TO_30") & First(필드!NON_STD_TXT.값, "ds_EXPLAN_SN_31_TO_45")
우리는 보안상의 제약으로 인해 DB Group에서 기능 등을 만들어야 합니다.따라서 약간의 창의성으로 사용자 집계나 UDF를 수행할 필요가 없었습니다.
애플리케이션에 집약에 사용하는 SN의 종류가 있는 경우는, 이 방법이 유효합니다.동등한 TSQL이 무엇인지 모르겠습니다.LISTAGG가 Godsend인 이 보고서를 위해 Oracle과 거래하게 되어 다행입니다.
코드는 다음과 같습니다.
SELECT
LT.C_O_NBR AS LT_CO_NUM,
RT.C_O_NBR AS RT_CO_NUM,
LT.STD_LN_ITM_NBR,
RT.NON_STD_LN_ITM_NBR,
RT.NON_STD_PRJ_NBR,
LT.STD_PRJ_NBR,
NVL(LT.PRPSL_LN_NBR, RT.PRPSL_LN_NBR) AS PRPSL_LN_NBR,
LT.STD_CO_EXPL_TXT AS STD_TXT,
LT.STD_CO_EXPLN_T,
LT.STD_CO_EXPL_SN,
RT.NON_STD_CO_EXPLN_T,
LISTAGG(RT.RMRKS_TXT_FLD, '')
WITHIN GROUP(ORDER BY RT.RMRKS_SN) AS NON_STD_TXT
FROM ...
WHERE RT.RMRKS_SN BETWEEN 0 AND 15
GROUP BY
LT.C_O_NBR,
RT.C_O_NBR,
...
나머지 2개의 데이터 세트에서는 FROM의 하위 쿼리에 대해서만 LISTAGG를 선택합니다.
SELECT
LISTAGG(RT.RMRKS_TXT_FLD, '')
WITHIN GROUP(ORDER BY RT.RMRKS_SN) AS NON_STD_TXT
송신원...
WHERE RT.RMRKS_SN BETWEEN 31 AND 45
...
... 등등.
CLOB를 사용하여 12c 오버플로를 사용하지 않는 한 기판도 작동합니다.
rtrim(dbms_lob.substr(XMLAGG(XMLLEAMENT(E,column_name',)')).EXCRECT('//text()') ORDER BY column_name).GetClobVal(), 1000,1','',')
집약을 완료하고 XML/HTML 컨텐츠 및 유니코드 문자를 처리하려면 다음을 사용합니다.
SELECT uuid, XMLCAST(XMLAGG(XMLELEMENT(E, TO_NCLOB(text),'') ORDER BY uuid) AS NCLOB) AS text
GROUP BY UUID
- XMLCAST는 XML/HTML의 부호화를 방지합니다.
- TO_NCLOB는 Unicode 문자를 "?"로 바꿉니다(이상적이지는 않지만 쿼리 브레이크보다 우수합니다).
XML/HTML만 처리하고 Unicode 문자에 대해 걱정할 필요가 없다면 다음을 사용할 수 있습니다.
SELECT uuid, XMLCAST(XMLAGG(XMLELEMENT(E, TO_CLOB(text),'') ORDER BY uuid) AS CLOB) AS text
GROUP BY UUID
이 접근법의 유일한 단점은 그룹화된 열과 집계할 열만 선택할 수 있다는 것입니다.결과를 다른 열에 포함하려면 Common Table Expression(CTE; 공통 테이블 식)에 배치하고 Group By 열과 같은 테이블에 결합해야 합니다.
라는 이름의 커스텀 기능을 사용하고 있습니다.clob_agg
다음과 같이 합니다.
select clob_agg(*detail_column*)
from *table*
group by *group_column*
실제 예:
select length(clob_agg(x||'')) fullList
from (select level as x
from dual
connect by level < 40000)
은 다음과 같습니다.228887
> :)==> 출력 길이
정의 함수(sqlDeveloper, dataGrip 또는 일부 다른 편집기에서 실행할 수 없는 경우 사용):
CREATE OR REPLACE TYPE t_clob_agg AS OBJECT
(
g_string clob,
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT t_clob_agg)
RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT t_clob_agg,
value IN clob)
RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateTerminate(self IN t_clob_agg,
returnValue OUT clob,
flags IN NUMBER)
RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateMerge(self IN OUT t_clob_agg,
ctx2 IN t_clob_agg)
RETURN NUMBER
);
/
SHOW ERRORS
CREATE OR REPLACE TYPE BODY t_clob_agg IS
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT t_clob_agg)
RETURN NUMBER IS
BEGIN
sctx := t_clob_agg(NULL);
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT t_clob_agg,
value IN clob)
RETURN NUMBER IS
BEGIN
-- Concatenate string only when not already existing in the list (=unique)
SELF.g_string := self.g_string || ',' || value;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateTerminate(self IN t_clob_agg,
returnValue OUT clob,
flags IN NUMBER)
RETURN NUMBER IS
BEGIN
returnValue := RTRIM(LTRIM(SELF.g_string, ','), ',');
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateMerge(self IN OUT t_clob_agg,
ctx2 IN t_clob_agg)
RETURN NUMBER IS
BEGIN
SELF.g_string := SELF.g_string || ',' || ctx2.g_string;
RETURN ODCIConst.Success;
END;
END;
/
SHOW ERRORS
CREATE OR REPLACE FUNCTION clob_agg(p_input clob)
RETURN clob
PARALLEL_ENABLE AGGREGATE USING t_clob_agg;
/
SHOW ERRORS
언급URL : https://stackoverflow.com/questions/13795220/listagg-function-result-of-string-concatenation-is-too-long
'programing' 카테고리의 다른 글
ASMX, ASPX 또는 ASHX에 대한 .NET AJAX 콜 (0) | 2023.03.05 |
---|---|
Angular에서 ng-options를 사용하여 선택을 필터링하려면 어떻게 해야 합니까? (0) | 2023.03.05 |
재료.UI 선택 설정 값이 항상 범위를 벗어남 (0) | 2023.03.05 |
커스터마이즈된HTPHeader 필드를 갖춘 JSON Post (0) | 2023.03.05 |
JSON 오브젝트 Node.js 작성 방법 (0) | 2023.03.05 |