2013-01-16 83 views
0

我有一個非常長的查詢,跨多個表,我連接了四個值作爲所有者(第一,中間名和最後一個名字+ org)。所有其他列是相同的,但有多個所有者,因此,我想要聚合多行。同一列中的多個值作爲連接字符串聚合(10g)

我所看到的是(配對向下)

#  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...但這殺死我的連接:

    Error- "No more data to read from socket"

    系統管理員,不知道爲什麼

  • 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)", 

對不起,忘了包括。

+0

沒有人回答,因爲我錯誤地問了嗎?我對唐的編輯有點困惑,可能他是這麼想的,因爲我的研究不夠深入? – user1983682

+0

不,你問得很好,據我所知。有些人認爲每個關鍵詞都應該標註爲代碼,但我們到達這裏的時間很長,但與您無關。人們可能只是不知道答案,就是這樣。那麼,盡我所能提高可讀性並添加相關標籤,因爲我們正在談論用SQL來做它,對吧? –

+0

是的,謝謝。 – user1983682

回答

5

不知道爲什麼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只是放在名稱,這是不完全相關的,我cast ing到varchar2,因爲wm_concat返回clob這會導致問題級聯org。至少,這是一個clob在11gR2 - 我沒有一個10g實例與wm_concat可用,但我認爲它在早期版本返回varchar2;如果是的話不需要cast,這將是更喜歡:

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

我不知道您的org值從所以這可能是簡化來了,我不知道你想什麼如果org與某人(而非問題或您的等價物)相關聯,並且問題有兩個擁有不同org值的所有者,則會發生這種情況。


如果這不是讓你更近,那麼也許你可以發表你的查詢的簡化版本,與一些固定的數據替換長多臺部分,展示你是如何嘗試使用wm_concat反對;或者你自己版本的示例數據 - 構建,顯示相同的行爲。


替代sys_connect_by_path方法,建議Appleman1234,對於同樣的數據:

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應該添加一個答案,我會刪除此部分,因爲他應該得到建議它的功勞!無論如何,我想嘗試它,我以前看過它,但沒有記住它...

+0

@ user1983682 - 關於你的'字符串緩衝區太小'錯誤;你想用'wm_concat'連接多少個值?結果是一個10g的'varchar2',它將被限制在4k(或32k,但我認爲是4k!);無論如何你仍然可以將它投射到1K。如果你有更多的值,你不介意丟失列表的末尾,你可以限制傳遞給它的行數,但是你必須設置一個足夠低的數字,以確保你永遠不會碰到限制。 –

+0

這只是最多三個人的第一個,中間和最後一個名字,如果我能解決的話,也許還是org。問題是我看到這個:Mark M. Majors,Mark M. Majors,Mark M. Majors ....「我不確定它爲什麼一遍又一遍地重複相同的值,可能會導致錯誤。 – user1983682

+0

@ user1983682 - 4k限制是針對總結果長度,而不是每個名稱的長度;例如,如果您允許每個名稱使用16個字符,那麼您只能使用256個名稱。三個人不應該成爲一個問題。但重複看起來像是來自底層數據;如果你運行沒有'wm_concat'的查詢,你有沒有重複? –

相關問題