我看到上一个问题,其中表格中包含“No”和“Name”列,以及其他与数字列组合在一起但却无法实现为我的案例提供的答案的问题。我需要做同样的事情,但是使用非数字分组。源表是tbl1,包含以下列:
POD Name
--- -----
North Rony
North James
North Aby
South Sam
South Willy
West Mike
我需要做这个聚合:
POD Name
--- -----
North Aby,James,Rony
South Sam,Willy
West Mike
由于“POD”不是数字,Msyma,Dinup和chetan以前的解决方案似乎对我没用。
我不知道如何根据这些要求的答案进行知识转移。
理想的查询是
SELECT POD, AGGREGATESTRING(Name)
FROM tbl1
GROUP BY POD
在理想示例中,AGGREGATESTRING不会对人名进行排序,但我认为我可以在需要时插入“ORDER BY”。
答案 0 :(得分:2)
Oracle 11g有这个简洁的功能LISTAGG几乎是你想要的,但是因为你使用的是10g,所以你无法使用(除非你决定升级)。
如果由于某种原因你不希望(或因为什么原因不能)升级到11g,我建议你看一下10g上可用的LISTAGG替代品。
您可以查看一些建议的替代方案here
快速调整其中一个建议替代方案的快速调整,以符合您的情况:
WITH Q AS
(
SELECT 'North' POD, 'Rony' NAME FROM DUAL UNION ALL
SELECT 'North', 'James' FROM DUAL UNION ALL
SELECT 'North', 'Aby' FROM DUAL UNION ALL
SELECT 'South', 'Sam' FROM DUAL UNION ALL
SELECT 'South', 'Willy' FROM DUAL UNION ALL
SELECT 'West', 'Mike' FROM DUAL
)
SELECT POD,
RTRIM(
XMLAGG (XMLELEMENT(e, name||',') ORDER BY name).EXTRACT('//text()'),
','
) AS name
FROM q
GROUP BY POD;
但请记住,这不是实际的解决方案,因为您必须根据您的表(而不是虚拟DUAL表)等来定制它......
您的解决方案可能看起来像是:
SELECT POD,
RTRIM(
XMLAGG (XMLELEMENT(E, NAME||',') ORDER BY NAME).EXTRACT('//text()'),
','
) AS NAME
FROM tbl1
GROUP BY POD;
如果要更改分隔符,可以在此部分中使用逗号进行更改:
(E, NAME||',')
RTRIM只是为了从串联字符串的末尾剪掉尾随的逗号,如果你没有被尾随的逗号打扰,你可以省略RTRIM函数以节省可读性。
答案 1 :(得分:2)
还有一种方式WM_CONCAT
with Q as
(select 'North' POD, 'Rony' name
from DUAL
union all
select 'North', 'James'
from DUAL
union all
select 'North', 'Aby'
from DUAL
union all
select 'South', 'Sam'
from DUAL
union all
select 'South', 'Willy'
from DUAL
union all
select 'West', 'Mike' from DUAL)
select pod, to_char(wm_concat(name)) as name from q group by pod
带分层查询的字符串聚合
with Q as
(select 'North' POD, 'Rony' name
from DUAL
union all
select 'North', 'James'
from DUAL
union all
select 'North', 'Aby'
from DUAL
union all
select 'South', 'Sam'
from DUAL
union all
select 'South', 'Willy'
from DUAL
union all
select 'West', 'Mike' from DUAL)
select pod, group_name
from (select t1.*, level as lv, substr(sys_connect_by_path(name, ','), 2) as group_name
from (select t1.*, nvl(lag(row_rank) over(partition by pod order by row_rank), 0) as parent_row_rank
from (select q.*,
rank() over(partition by pod order by name) as row_rank,
rank() over(partition by pod order by name desc) as row_rank_desc
from q) t1) t1
where row_rank_desc = 1
connect by prior row_rank = parent_row_rank
and prior pod = pod
start with parent_row_rank = 0) t1
答案 2 :(得分:0)
我只能在Oracle 11g R2上测试它;但是,我相信Oracle 10g也可以使用所有内容。
这里包含两个功能,两个功能都使用集合:
DBMS_LOB
包并且更加冗长,但是在我的测试中,似乎效率更高(尽管我建议您自己进行分析以测试它)。Oracle 11g R2架构设置:
对于此方法,您需要定义一个Collection以将字符串聚合到:
CREATE OR REPLACE TYPE VARCHAR2s_Table AS TABLE OF VARCHAR2(4000);
/
此函数接受一个字符串集合(和一个可选的分隔符)并返回包含连接字符串的CLOB
- 如果您有一个较小的数据集(根据您的示例),那么这可能是过度的,您可以替换{ {1}} CLOB
。
VARCHAR2
但是,如果要将长字符串作为CREATE OR REPLACE FUNCTION concatStrings(
Strs VARCHAR2s_Table,
delim VARCHAR2 DEFAULT ','
) RETURN CLOB
AS
out_string CLOB;
BEGIN
FOR i IN 1 .. Strs.COUNT LOOP
out_string := out_string || CASE WHEN i = 1 THEN '' ELSE delim END || Strs(i);
END LOOP;
RETURN out_string;
END;
/
返回,那么使用CLOB
包的某些功能可能更有效:
DBMS_LOB
您的测试数据:
CREATE OR REPLACE FUNCTION concatStrings2(
Strs VARCHAR2s_Table,
delim VARCHAR2 DEFAULT ','
) RETURN CLOB
AS
out_string CLOB;
dl CONSTANT NUMBER(10) := LENGTH( delim );
BEGIN
DBMS_LOB.CREATETEMPORARY( out_string, TRUE );
IF strs IS NOT NULL AND strs IS NOT EMPTY THEN
IF dl > 0 THEN
DBMS_LOB.WRITEAPPEND( out_string, LENGTH( strs(1) ), strs(1) );
FOR i IN 2 .. strs.COUNT LOOP
DBMS_LOB.WRITEAPPEND( out_string, dl, delim );
DBMS_LOB.WRITEAPPEND( out_string, LENGTH( strs(i) ), strs(i) );
END LOOP;
ELSE
FOR i IN 1 .. strs.COUNT LOOP
DBMS_LOB.WRITEAPPEND( out_string, LENGTH( strs(i) ), strs(i) );
END LOOP;
END IF;
END IF;
RETURN out_string;
END concatStrings2;
/
查询1 :
CREATE TABLE tbl1 ( POD, name ) AS
SELECT 'North', 'Rony' FROM DUAL
UNION ALL SELECT 'North', 'James' FROM DUAL
UNION ALL SELECT 'North', 'Aby' FROM DUAL
UNION ALL SELECT 'South', 'Sam' FROM DUAL
UNION ALL SELECT 'South', 'Willy' FROM DUAL
UNION ALL SELECT 'West', 'Mike' FROM DUAL
/
<强> Results 强>:
SELECT POD,
concatStrings( CAST( COLLECT( name ORDER BY name ASC ) AS VARCHAR2s_Table )) AS name
FROM tbl1
GROUP BY POD
查询2 :
| POD | NAME |
|-------|----------------|
| North | Aby,James,Rony |
| South | Sam,Willy |
| West | Mike |
<强> Results 强>:
SELECT POD,
concatStrings2( CAST( COLLECT( name ORDER BY name ASC ) AS VARCHAR2s_Table )) AS name
FROM tbl1
GROUP BY POD
答案 3 :(得分:-1)
SELECT POD,WM_CONCAT(NAME) AS AGG_STRING FROM TEST_AV
GROUP BY POD;
----------------------------------------------------------------------------------
POD AGG_STRING
NORTH JANES,RONY,ABY
SOUTH WILLY
WEST MIKE
3 rows returned in 0.07 seconds