按组的 DB2 逗号分隔输出
Posted
技术标签:
【中文标题】按组的 DB2 逗号分隔输出【英文标题】:DB2 Comma Separated Output by Groups 【发布时间】:2011-11-03 13:12:52 【问题描述】:DB2 SQL
中是否有用于逗号分隔列值的内置函数?
示例:如果有带有ID
的列,并且它有3 行具有相同的ID
但具有三个不同的角色,则数据应该用逗号连接。
ID | Role
------------
4555 | 2
4555 | 3
4555 | 4
每行的输出应如下所示:
4555 2,3,4
【问题讨论】:
【参考方案1】: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 by 子句进行选择
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
【讨论】:
【参考方案2】:我认为通过这个较小的查询,你可以做你想做的事。 这相当于 DB2 中 mysql 的 GROUP_CONCAT。
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
【讨论】:
【参考方案3】:根据您拥有的 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 here 的更好解决方案。
【讨论】:
【参考方案4】:从 DB2 9.7.5 开始有一个函数:
LISTAGG(colname, separator)
查看更多信息:Using LISTAGG to Turn Rows of Data into a Comma Separated List
【讨论】:
【参考方案5】:我的问题是使用 CSV 将行字段 (CLOB) 转置为列 (VARCHAR) 并使用转置的表进行报告。因为在报表层上转置会减慢报表的速度。
一种方法是使用递归 SQL。您可以找到很多关于此的文章,但如果您想加入所有递归转置列,那么它既困难又耗费资源。
我创建了多个全局临时表,其中存储了带有一个键标识符的单个转置列。最终,我有 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') 作为 TRANSPOSED_OUTPUTRTRIM(REPLACE(REPLACE(REPLACE(VARCHAR(XMLSERIALIZE(XMLAGG(XMLELEMENT(NAME "A",ALIASNAME.ATTRIBUTENAME) ORDER BY ALIASNAME.ATTRIBUTENAME) AS CLOB)), '',','),'','') ,'','')) 作为 TRANSPOSED_OUTPUT
确保在子查询中将“ATTRIBUTENAME”转换为 varchar,然后在此处调用它。
【讨论】:
【参考方案6】:其他可能性,使用递归 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
【讨论】:
【参考方案7】:试试这个:
SELECT GROUP_CONCAT( field1, field2, field3 ,field4 SEPARATOR ', ')
【讨论】:
Field1: 1.4555 - SELECT GROUP_CONCAT(field1,,field3,field4 SEPARATOR ',') 你能构造你的问题吗?:D 这是 mysql 不是 db2以上是关于按组的 DB2 逗号分隔输出的主要内容,如果未能解决你的问题,请参考以下文章