【问题标题】:Aggregation of multiple values from same column as a concatenated string (10g)将同一列中的多个值聚合为连接字符串(10g)
【发布时间】:2012-12-30 19:51:53
【问题描述】:

我有一个很长的查询,跨越多个表,其中我连接了四个值作为所有者(名字、中间名和姓氏 + org)。所有其他列都相同,但有多个所有者,因此,我想聚合多行。

我看到的是(配对)

#     Owner
1     Sam Smith, AAA
2     Stan Bird, BBB
2     Nancy Bird, BBB
3     Mike Owen, CCC

我想看到的是

#     Owner
1     Sam Smith, AAA
2     Stan Bird, Nancy Bird, BBB
3     Mike Owen, CCC

注意事项:

  • 我无法创建函数(缺少权限)
  • 使用 Oracle 10g
  • 我尝试过CASE(COLLECT...,但这会中断我的连接:

    错误-“没有更多数据可以从套接字读取”

    系统管理员,不知道为什么

  • WM_CONCAT 只是重复一个所有者(有时 20 次),并没有给出预期的结果。

我尝试了其他一些方法,但没有成功。我当前的查询正在生成所需的行数,但只是删除了第二个所有者。

我不确定在此处发布整个查询是否明智。请让我知道这是否有帮助。


2012-01-29 更新

我之前错误地使用了wm_concat,但是当我按照您的说明使用它时,我收到了这个错误:

 ORA-06502: PL/SQL: numeric or value error: character string buffer too
 small ORA-06512: at "WMSYS.WM_CONCAT_IMPL", line 30
 06502. 00000 -  "PL/SQL: numeric or value error%s"
 *Cause:    
 *Action:

我相信可能存在一些更高级别的问题。我的系统管理员对“不再从套接字读取数据”问题没有答案。这可能是另一个。

我的SQL知识有限,加上查询的长度和复杂度,我似乎无法实现sys_connect_by_path;完全是我自己的错。

抱歉,回复延迟。我被拉走以完成另一项任务。感谢您的所有帮助。感谢 ShadowWizard 的赏金。

编辑
以下是我在当前实例中使用 wm_concat 的方式:

 replace(cast(wm_concat(PERSON.MASTER_PERSON_FIRST_NAME   || ' '   ||
 PERSON.MASTER_PERSON_MIDDLE_INITIAL   || ' '   ||
 PERSON.MASTER_PERSON_LAST_NAME   || ','   || ' '   ||
 ORGANIZATION.MASTER_ORG_NAME) AS VARCHAR2(1000 BYTE)), ',', ', ') AS
 "Owner(s)",

抱歉,忘记包含了。

【问题讨论】:

  • 因为我问错了没有人回答吗?我对 Don 的编辑有点困惑,认为他这样做可能是因为我没有进行足够的研究?
  • 不,据我所知,你问得很好。有些人认为每个关键字都应该标记为代码,这是我们很长时间的问题但实际上与您无关。人们可能只是不知道答案,仅此而已。好吧,尽我所能提高可读性并添加相关标签,因为我们正在谈论使用 SQL 来做这件事,对吧?
  • 好的,尝试在这里设置赏金作为吸引注意力的最后手段。 :)
  • 行号,sys connect by path method提到here对你有用吗?
  • 当你得到“No more data to read from socket”时,这通常意味着有一个严重的错误,这通常是一个Oracle错误。告诉您的 DBA 在错误发生时检查警报日志以查找 ORA-600 错误。

标签: sql oracle10g aggregate


【解决方案1】:

不知道为什么 wm_concat 对你不起作用,但我怀疑你的级别有误或分组奇怪。

如果我设置一些虚拟数据:

create table issues (id number);

create table owners (id number, first varchar2(10), middle varchar2(10),
    last varchar2(10), org varchar2(3));

create table issue_owners (issue_id number, owner_id number);

insert into issues (id) values (1);
insert into issues (id) values (2);
insert into issues (id) values (3);

insert into owners (id, first, middle, last, org)
    values (11, 'Sam', null, 'Smith', 'AAA');
insert into owners (id, first, middle, last, org)
    values (12, 'Stan', null, 'Bird', 'BBB');
insert into owners (id, first, middle, last, org)
    values (13, 'Nancy', null, 'Bird', 'BBB');
insert into owners (id, first, middle, last, org)
    values (14, 'Mike', null, 'Owen', 'CCC');

insert into issue_owners (issue_id, owner_id) values (1, 11);
insert into issue_owners (issue_id, owner_id) values (2, 12);
insert into issue_owners (issue_id, owner_id) values (2, 13);
insert into issue_owners (issue_id, owner_id) values (3, 14);

...它提供与配对样本相同的初始输出:

column issue_id format 9 heading "#"
column owner format a50 heading "Owner"

select i.id as issue_id,
    o.first
        || case when o.middle is null then null else ' ' || o.middle end
        || ' ' || last || ', ' ||o.org as owner
from issues i
left join issue_owners io on io.issue_id = i.id
left join owners o on o.id = io.owner_id
order by issue_id, owner;

 # Owner
-- --------------------------------------------------
 1 Sam Smith, AAA
 2 Nancy Bird, BBB
 2 Stan Bird, BBB
 3 Mike Owen, CCC

4 rows selected.

我可以使用wm_concat 来聚合名称:

select issue_id,
    replace(cast(wm_concat(owner_name) as varchar2(4000)), ',', ', ')
        || ', ' || owner_org as owner
from (
    select i.id as issue_id,
        o.first
            || case when o.middle is null then null else ' ' || o.middle end
            || ' ' || last as owner_name,
        o.org as owner_org
    from issues i
    left join issue_owners io on io.issue_id = i.id
    left join owners o on o.id = io.owner_id
)
group by issue_id, owner_org
order by issue_id, owner;

 # Owner
-- --------------------------------------------------
 1 Sam Smith, AAA
 2 Stan Bird, Nancy Bird, BBB
 3 Mike Owen, CCC

3 rows selected.

replace 只是在名称之间放置空格,这并不完全相关,我将 casting 到 varchar2,因为 wm_concat 返回一个 clob,这会导致连接org。至少,它是 11gR2 中的 clob - 我没有可用的 wm_concat 的 10g 实例,但我认为它在早期版本中返回 varchar2;如果是这样,则不需要cast,它更像是:

select issue_id,
    replace(wm_concat(owner_name), ',', ', ') || ', ' || owner_org as owner
from (
...

我不确定您的 org 值来自何处,因此这可能已简化,并且我不知道如果 org 与一个人相关联(而不是问题,或您的等价物)并且一个问题有两个拥有不同 org 值的所有者。


如果这没有让您更接近,那么也许您可以发布查询的精简版本,用一些固定数据替换长的多表部分,并展示您如何尝试使用 wm_concat 反对它;或您自己的显示相同行为的示例数据构建版本。


建议 Appleman1234 的替代 sys_connect_by_path 方法,用于相同的数据:

select issue_id,
    ltrim(max(sys_connect_by_path(owner_name, ', '))
        keep (dense_rank last order by curr), ', ')
        || ', ' || owner_org as owner
from (
    select issue_id,
        owner_name,
        owner_org,
        row_number() over (partition by issue_id order by owner_name) as curr,
        row_number() over (partition by issue_id order by owner_name) - 1 as prev
    from (
        select i.id as issue_id,
            o.first
                || case when o.middle is null then null else ' ' || o.middle end
                || ' ' || last as owner_name,
            o.org as owner_org
        from issues i
        left join issue_owners io on io.issue_id = i.id
        left join owners o on o.id = io.owner_id
    )
)
group by issue_id, owner_org
connect by prev = prior curr and issue_id = PRIOR issue_id
start with curr = 1;

 # Owner
-- --------------------------------------------------
 1 Sam Smith, AAA
 2 Nancy Bird, Stan Bird, BBB
 3 Mike Owen, CCC

3 rows selected.

如果你最终使用了它,Appleman1234 应该添加一个答案,我会删除这部分,因为他的建议应该得到赞誉!反正我也想试试,以前看过但不记得了……

【讨论】:

  • @user1983682 - 关于您的character string buffer too small 错误;您要与wm_concat 连接多少个值?结果是 10g 中的varchar2,它将被限制为 4k(或 32k,但我认为是 4k!);尽管无论如何您都将其转换为1k。如果你有更多的值并且你不介意丢失列表的末尾,你可以限制传递给它的行数,但你必须设置一个足够低的数字以确保你永远不会碰到限制。
  • 这只是名字、中间名和姓氏,最多三个人,如果我能解决的话,也许是 org。问题是我看到了这个:Mark M. Majors, Mark M. Majors, Mark M. Majors....我不确定为什么它一遍又一遍地重复相同的值,可能导致错误。
  • @user1983682 - 4k 限制是针对总结果长度,而不是每个名称的长度;例如,如果您允许每个名称包含 16 个字符,那么您只能容纳 256 个名称。三个人应该不是问题。但是重复看起来像是来自基础数据;如果您在没有 wm_concat 的情况下运行查询,是否有重复项?
  • It's a 4k limit for the total length of the string Alex(我想我是在 11g 中运行的),cc @user1983682
  • @Ben - 是的,这就是我在之前的评论中试图澄清的内容,显然不是很成功!似乎预期的数据不应该接近那个,所以我认为传入的数据有问题......
猜你喜欢
  • 2013-06-23
  • 1970-01-01
  • 2020-12-07
  • 1970-01-01
  • 2018-10-27
  • 2012-04-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多