Объединение слишком длинное

Скажем, у меня есть эта таблица:

ID|Col1|Col2|Col3

1|Text that has 4000 chars|Text2 that has 4000 chars|Text3 that has 4000 chars

2|Text4 that has 4000 chars|Text5 that has 4000 chars|Text6 that has 4000 chars

3|Text7 that has 4000 chars|Text8 that has 4000 chars|Text9 that has 4000 chars

Я использую listagg так:

SELECT id,
       listagg(col1||col2||col3, ',') within group (order by id)
FROM table;

И я сталкиваюсь с ошибкой:

ORA-01489: result of string concatenation is too long

Проведя исследование, я обнаружил, что с помощью xmlagg можно добиться цели (ссылка), но затем понял, реальная проблема заключается в объединении col1, col2 и col3, поскольку оно ограничено только 4000 символов, поэтому выполнение xmlagg все равно вернет ту же ошибку.

Кто-нибудь уже разобрался с этим? Или нет обходного пути для этого? (ссылка)

Обновлять:

Я обновил примеры значений в таблице просто для ясности (чтобы г-н Кумар понял), и мой ожидаемый результат должен быть примерно таким:

ID | Agg
1 | Text that has 4000 charsText2 that has 4000 charsText3 that has 4000 chars
2 | Text4 that has 4000 charsText5 that has 4000 charsText6 that has 4000 chars
3 | Text7 that has 4000 charsText8 that has 4000 charsText9 that has 4000 chars

Что видимо не работает.


person superigno    schedule 02.12.2015    source источник
comment
но затем понял, что реальная проблема заключается в объединении столбцов col1, col2 и col3, поскольку оно ограничено только 4000 символов, поэтому выполнение xmlagg все равно вернет ту же ошибку. Нет. Вам нужно объединить XMLAGG вывод каждого столбца. Например, rtrim(xmlagg(xmlelement(e,col1,',').extract('//text()') order by col1).GetClobVal(),',')||rtrim(xmlagg(xmlelement(e,col2,',').extract('//text()') order by col2).GetClobVal(),',')   -  person Lalit Kumar B    schedule 02.12.2015
comment
Неа. Это вернет: Текст в col1 row1, Текст в col1 row2, Текст в col1 row3 Текст в col2 row1, Текст в col2 row2, Текст в col2 row3 Текст в col3 row1, Текст в col3 row2, Текст в col3 row3 Вместо: Text на col1 row1, Текст на col2 row1, Текст на col3 row1 Текст на col1 row2, Текст на col2 row2, Текст на col3 row2 Текст на col1 row3, Текст на col2 row3, Текст на col3 row3   -  person superigno    schedule 02.12.2015
comment
Я попробовал это, и он вернул значения, которые я ожидал, что он вернет, как упоминалось в моем предыдущем комментарии.   -  person superigno    schedule 02.12.2015
comment
Возвращаемые значения: один, два, три... двести сорок девять один, два, три... двести сорок девять вместо одного, одного, двух, двух, трех, трех... двухсот сорока девяти, двести сорок девять   -  person superigno    schedule 02.12.2015
comment
Неа. Это не сработало.   -  person superigno    schedule 02.12.2015
comment
Вы просто повторяете то, о чем я говорил выше. Моя проблема будет заключаться в том, что если значение col1 или col2 больше 4000 символов, оно все равно вызовет исключение.   -  person superigno    schedule 02.12.2015
comment
Я думаю, вы не понимаете мою мысль. Он должен работать во всех случаях (если только вы напрямую не объединяете две строки по 4000 байт, поскольку вы не можете использовать ограничение SQL). Итак, вам нужно сделать это так, как SET LONG 2000000 set pagesize 50000 WITH DATA AS ( SELECT rpad('a',4000,'*') col1, rpad('b',4000,'*') col2 FROM dual ) SELECT rtrim(xmlagg(XMLELEMENT(e,col1,',').EXTRACT('//text()')).GetClobVal(),',') || rtrim(xmlagg(XMLELEMENT(e,col2,',').EXTRACT('//text()')).GetClobVal(),',') very_long_text FROM DATA; col1 и col2 каждый по 4000 байт, в результате конкатенации получается 8000 байт.   -  person Lalit Kumar B    schedule 02.12.2015
comment
Ну вот. Это ответ, который я искал, если только вы напрямую не объедините две строки по 4000 байт, поскольку вы не можете это ограничить SQL. Это бы меня удовлетворило. Вы даже цитировали меня ранее, но потом поняли, что настоящая проблема заключается в объединении col1, col2 и col3, поскольку оно ограничено только 4000 символов, поэтому выполнение xmlagg все равно вернет ту же ошибку. но затем вы предоставили ненужные ответы. Спасибо, в любом случае.   -  person superigno    schedule 02.12.2015
comment
Вот почему я дал вам новый запрос, который объединил бы выходные данные XMLAGG с более чем 4000 байтами. В приведенном выше примере выходные данные объединяются в 8000 байт. И это не были лишние ответы, поскольку они были другими. Я потратил все время, чтобы помочь вам.   -  person Lalit Kumar B    schedule 02.12.2015
comment
Что не удовлетворяло вопрос.   -  person superigno    schedule 02.12.2015
comment
Давайте продолжим обсуждение в чате.   -  person Lalit Kumar B    schedule 02.12.2015


Ответы (2)


Вы можете сделать это намного проще, поскольку Oracle представила семантику SQL и LOB некоторое время назад.

SELECT ID, TO_CLOB(col1) || col2 || col3 AS very_long_text
FROM TABLE;

Первый элемент оператора || должен быть CLOB, тогда он работает.

person Wernfried Domscheit    schedule 02.12.2015
comment
XMLAGG также возвращает CLOB, поэтому ограничение varchar2 в 4000 байт отсутствует. - person Lalit Kumar B; 02.12.2015
comment
Однако я получаю это: ORA-22835: буфер слишком мал для преобразования CLOB в CHAR или BLOB в RAW (фактическое: 8002, максимальное: 4000) - person superigno; 03.12.2015
comment
Используя это: SELECT id, listagg(TO_CLOB(col1)||col2||col3, ',') внутри группы (порядок по id) FROM table; - person superigno; 03.12.2015
comment
Почему вы вообще используете LISTAGG? Не требуется для желаемого результата - person Wernfried Domscheit; 03.12.2015

Наконец-то я заработал. Что я сделал, так это объединил столбцы перед их объединением, СГРУППИРОВАЛ их, как предложил г-н Кумар, а ЗАТЕМ снова объединил их, чтобы исправить порядок. Вот как:

WITH agg_tbl AS
(
SELECT id,
       rtrim(xmlagg(xmlelement(e,col1,',').extract('//text()').GetClobVal(),',')||rtrim(xmlagg(xmlelement(e,col1,',').extract('//text()').GetClobVal(),',')||rtrim(xmlagg(xmlelement(e,col1,',').extract('//text()').GetClobVal(),',') long_text
FROM table
GROUP BY col1
)
SELECT rtrim(xmlagg(xmlelement(e,long_text,chr(13)).extract('//text()').GetClobVal(),',') agg_value
FROM agg_tbl;

Итак, вместо этого:

agg_value
Text that has 4000 charsText4 that has 4000 charsText7 that has 4000 chars
Text2 that has 4000 charsText5 that has 4000 charsText8 that has 4000 chars
Text3 that has 4000 charsText6 that has 4000 charsText9 that has 4000 chars

Теперь я получаю желаемый результат:

agg_value
Text that has 4000 charsText2 that has 4000 charsText3 that has 4000 chars
Text4 that has 4000 charsText5 that has 4000 charsText6 that has 4000 chars
Text7 that has 4000 charsText8 that has 4000 charsText9 that has 4000 chars
person superigno    schedule 03.12.2015
comment
Рад, что ты наконец это понял! +1 Вы можете пометить свой ответ как правильный, тогда я удалю свой. В любом случае за это проголосовали! - person Lalit Kumar B; 03.12.2015
comment
Спасибо @LalitKumarB! Ваше здоровье - person superigno; 03.12.2015