Разделенный запятыми вывод DB2 по группам
Есть ли встроенная функция для значений столбцов, разделенных запятыми, в DB2 SQL
?
Пример: Если есть столбцы с ID
и в нем 3 строки с одинаковым ID
, но имеют три разные роли, данные должны быть объединены запятой.
ID | Role
------------
4555 | 2
4555 | 3
4555 | 4
Вывод должен выглядеть следующим образом для каждой строки:
4555 2,3,4
Ответы
Ответ 1
Это именно то, что вам нужно:
http://radheshk.blogspot.com/2008/02/sql-tips-techniques-string-aggregation.html
К сожалению, нет возможности легко определить пользовательскую агрегатную функцию в DB2 (или не знаю, что я знаю). Поэтому нужно обращаться к рекурсивным запросам, как в приведенном выше примере.
Еще один способ решить эту проблему - курсоры, но это, вероятно, еще хуже...
Ответ 2
Функция LISTAGG - это новая функция в DB2 LUW 9.7
см. пример:
create table myTable (id int, category int);
insert into myTable values (1, 1);
insert into myTable values (2, 2);
insert into myTable values (5, 1);
insert into myTable values (3, 1);
insert into myTable values (4, 2);
пример: выберите без какого-либо заказа в сгруппированном столбце
select category, LISTAGG(id, ', ') as ids from myTable group by category;
результат:
CATEGORY IDS
--------- -----
1 1, 5, 3
2 2, 4
пример: выберите с положением order в сгруппированном столбце
select
category,
LISTAGG(id, ', ') WITHIN GROUP(ORDER BY id ASC) as ids
from myTable
group by category;
результат:
CATEGORY IDS
--------- -----
1 1, 3, 5
2 2, 4
Ответ 3
Я думаю, что с этим меньшим запросом вы можете делать то, что хотите.
Это эквивалентно MySQL GROUP_CONCAT в DB2.
SELECT
NUM,
SUBSTR(xmlserialize(xmlagg(xmltext(CONCAT( ', ',ROLES))) as VARCHAR(1024)), 3) as ROLES
FROM mytable
GROUP BY NUM;
Это приведет к тому, что:
NUM ROLES
---- -------------
1 111, 333, 555
2 222, 444
Умножение вашего исходного результата было примерно таким:
NUM ROLES
---- ---------
1 111
2 222
1 333
2 444
1 555
Ответ 4
В зависимости от версии DB2 вы можете использовать функции XML для достижения этой цели.
Пример таблицы с некоторыми данными
create table myTable (id int, category int);
insert into myTable values (1, 1);
insert into myTable values (2, 2);
insert into myTable values (3, 1);
insert into myTable values (4, 2);
insert into myTable values (5, 1);
Совокупные результаты с использованием функций xml
select category,
xmlserialize(XMLAGG(XMLELEMENT(NAME "x", id) ) as varchar(1000)) as ids
from myTable
group by category;
результаты:
CATEGORY IDS
-------- ------------------------
1 <x>1</x><x>3</x><x>5</x>
2 <x>2</x><x>4</x>
Используйте замену, чтобы результат выглядел лучше
select category,
replace(
replace(
replace(
xmlserialize(XMLAGG(XMLELEMENT(NAME "x", id) ) as varchar(1000))
, '</x><x>', ',')
, '<x>', '')
, '</x>', '') as ids
from myTable
group by category;
Очищенный результат
CATEGORY IDS
-------- -----
1 1,3,5
2 2,4
Просто увидел лучшее решение, использующее XMLTEXT вместо XMLELEMENT здесь.
Ответ 5
Так как DB2 9.7.5 для этого есть функция:
LISTAGG(colname, separator)
проверьте это для получения дополнительной информации: Использование LISTAGG для превращения строк данных в разделенный запятыми список
Ответ 6
Моя проблема заключалась в том, чтобы транспонировать поля строк (CLOB) в столбец (VARCHAR) с помощью CSV и использовать транспонированную таблицу для отчетности. Поскольку перенос на уровне отчета замедляет отчет.
Один из способов - использовать рекурсивный SQL. Вы можете найти много статей об этом, но это сложный и ресурсоемкий, если вы хотите присоединиться ко всем рекурсивным транспонированным столбцам.
Я создал несколько глобальных temp-таблиц, где я сохранил одиночные транспонированные столбцы с одним ключевым идентификатором. В конце концов, у меня было 6 временных таблиц для присоединения к 6 столбцам, но из-за ограниченного распределения ресурсов я не смог собрать все столбцы. Я выбрал менее 3 формулы, а затем мне просто пришлось запустить 1 запрос, который дал мне результат через 10 секунд.
Я нашел различные статьи об использовании функций XML2CLOB и нашел 3 разных способа.
REPLACE(VARCHAR(XML2CLOB(XMLAGG(XMLELEMENT(NAME "A",ALIASNAME.ATTRIBUTENAME)))),'', ',') AS TRANSPOSED_OUTPUT
NVL(TRIM(',' FROM REPLACE(REPLACE(REPLACE(CAST(XML2CLOB(XMLAGG(XMLELEMENT(NAME "E", ALIASNAME.ATTRIBUTENAME))) AS VARCHAR(100)),'',' '),'',','), '', 'Nothing')), 'Nothing') as TRANSPOSED_OUTPUT
RTRIM(REPLACE(REPLACE(REPLACE(VARCHAR(XMLSERIALIZE(XMLAGG(XMLELEMENT(NAME "A",ALIASNAME.ATTRIBUTENAME) ORDER BY ALIASNAME.ATTRIBUTENAME) AS CLOB)), '',','),'',''),'','')) AS TRANSPOSED_OUTPUT
Убедитесь, что вы вставляете свой "ATTRIBUTENAME" в varchar в подзапрос, а затем вызываете его здесь.
Ответ 7
другая возможность, с рекурсивным cte
with tablewithrank as (
select id, category, rownumber() over(partition by category order by id) as rangid , (select count(*) from myTable f2 where f1.category=f2.category) nbidbycategory
from myTable f1
),
cte (id, category, rangid, nbidbycategory, rangconcat) as (
select id, category, rangid, nbidbycategory, cast(id as varchar(500)) from tablewithrank where rangid=1
union all
select f2.id, f2.category, f2.rangid, f2.nbidbycategory, cast(f1.rangconcat as varchar(500)) || ',' || cast(f2.id as varchar(500)) from cte f1 inner join tablewithrank f2 on f1.rangid=f2.rangid -1 and f1.category=f2.category
)
select category, rangconcat as IDS from cte
where rangid=nbidbycategory
Ответ 8
Попробуйте следующее:
SELECT GROUP_CONCAT( field1, field2, field3 ,field4 SEPARATOR ', ')