2010-12-07 10 views
0

この同じ質問について複数の質問がありますが、私の問題を解決するものは見つかりませんでした。私もこのことについてはarticleを知っている、それは私が以下のコードのために使ったものです。私はほんの少し問題を抱えている...複数の行を1つの列に結合する関連するテーブルが3つあるOracleの関数

table_a:

a_id a_name 
1  aaa 
2  bbb 
3  ccc 

table_b:

b_id b_name 
1  ddd 
2  eee 
3  fff 

table_c

a_id b_id 
1  2 
1  3 
2  1 
3  1 
3  2 
3  3 

私は上記の表があると私はこれを達成するSELECTステートメントを必要とする:

a_name list_of_b_name 
aaa  eee,fff 
bbb  ddd 
ccc  ddd,eee,fff 

はたぶんWM_CONCAT(試していない)のような私は、プロセスを簡素化するために使用できるいくつかのOracleの機能は、ありますが、私のようにする必要がありFUNCTIONを使用し、これは上記のリンク先の記事を見た後に私の試みです:

CREATE OR REPLACE 
FUNCTION f_test(id IN table_c.a_id % TYPE) RETURN VARCHAR2 IS 
    l_text VARCHAR2(32767) := NULL; 
BEGIN 
    FOR cur_rec IN (SELECT b_id FROM table_c WHERE a_id = id) LOOP 
    l_text := l_text || ',' || cur_rec.b_id; 
    END LOOP; 
    RETURN LTRIM(l_text, ','); 
END; 

そしてSELECTはこのように書きます:コードAによって期待されるよう

SELECT a_id, f_test(a_id) 
FROM table_c 
GROUP BY a_id; 

BOVE(ないない私が欲しいもの、これは私が得るものです):

a_id list_of_b_id 
1  2,3 
2  1 
3  1,2,3 

私はSELECTおよび機能コードの両方で多くのことを試みたが、私は私が必要なものをやるように見えることはできません...

答えて

1

あなたが似ているようにあなたの関数を変更する必要があります。

CREATE OR REPLACE FUNCTION f_test(IN_ID IN TABLE_C.a_id%TYPE) 
RETURN VARCHAR2 
IS 

    l_text VARCHAR2(32767) := NULL; 

BEGIN 

    FOR cur_rec IN (SELECT b.b_name 
        FROM TABLE_B b 
        JOIN TABLE_C c ON c.b_id = b.b_id 
        WHERE c.a_id = IN_ID) LOOP 
    l_text := l_text || ',' || cur_rec.b_id; 
    END LOOP; 

    RETURN LTRIM(l_text, ','); 

END; 

を次に、あなたが使用することができます。

SELECT a.a_name, 
     f_test(a.a_id) 
    FROM TABLE_A a 
1

変更SQLクエリへの代わりに、表BからIDを取得する、あなたの代わりに名を取得する必要があります

SELECT b_name 
    FROM table_b b, table_c c 
    WHERE b.b_id = c.c_id 
    and b.a_id = id 

にbnames代わりの

SELECT b_id FROM table_c WHERE a_id = id 

からb_ids

のリストを取得します。

0

まず、@OMGPoniesが指摘するように、TABLE_Bから必要なデータを取得するように関数を書き直す必要があります。

SQL> create or replace function f_test 
    2  (p_id in table_c.a_id%type) 
    3  return varchar2 
    4 is 
    5  l_text varchar2(32767) := null; 
    6 begin 
    7  for cur_rec in (select b_name 
    8      from table_c c 
    9        join table_b b 
10         on (b.b_id = c.b_id) 
11      where c.a_id = p_id) 
12  loop 
13   l_text := l_text || ',' || cur_rec.b_name; 
14  end loop; 
15  return ltrim(l_text, ','); 
16 end; 
17/

Function created. 

SQL> 

同様にクエリでTABLE_Aに参加する必要があります。

SQL> select a.a_name 
    2   , f_test(c.a_id) 
    3 from table_c c 
    4   join table_a a 
    5    on (a.a_id = c.a_id) 
    6 group by a.a_name 
    7/
     , f_test(c.a_id) 
       * 
ERROR at line 2: 
ORA-00979: not a GROUP BY expression 


SQL> 

驚きだったああ、。

SQL> select a.a_name 
    2   , f_test(c.a_id) 
    3 from table_c c 
    4   join table_a a 
    5    on (a.a_id = c.a_id) 
    6 group by a.a_name, f_test(c.a_id) 
    7/

A_N F_TEST(C.A_ID) 
--- --------------------------------------------- 
bbb ddd 
ccc ddd,eee,fff 
aaa eee,fff 

SQL> 

ちなみに(私たちは6行になるだろうGROUP BY句なしで、それぞれに1つずつ:ポイントは、我々は、同様の機能が含まれない限り、GROUP BYはここで働いていないのでF_TESTは、集計関数ではありません、ですTABLE_Cの行)。私たちは欲しくない。

解決策の問題は、パフォーマンスの1つです。この関数は、TABLE_Cの各行に対して1回実行されます。どちらの表が大きい場合でも、TABLE_Bのループは少し高価になります。

SQL> select a.a_name 
    2   , wm_concat(b.b_name) 
    3 from table_c c 
    4   join table_b b 
    5    on (b.b_id = c.b_id) 
    6   join table_a a 
    7    on (a.a_id = c.a_id) 
    8 group by a.a_name 
    9/

A_N WM_CONCAT(B.B_NAME) 
--- --------------------------------------------- 
aaa fff,eee 
bbb ddd 
ccc fff,eee,ddd 

SQL> 
+0

GROUP BY関数を使用する必要はなく、関数外でJOINを行う必要はありません。 –

+0

@OMGPonies - TABLE_Aを実行するために関数とクエリを実装しているため、ソリューションには当てはまります。 OPは何か違ったものを投稿し、それを実装しました。 TABLE_CにないレコードがTABLE_Cにない場合、解決策は私のものとは異なる結果セットを返します(TABLE_Cに参加するためのクエリを修正しない限り、私はそれが優秀ではないと思います - 同じテーブルで2つ選択する)。今では、TABLE_Aのすべての行についてTABLE_Cに行が常に存在するかもしれませんが、OPはそのビジネスルールを私たちに保証していません。 – APC

+0

残念ながら、細かいことを少しでも覚えているのは難しいです...そして、はい、TABLE_CのTABLE_Aからのエントリが常に存在します。ごめんなさい。 –

関連する問題