Sql 使用Oracle中带有3个相关表的函数将多行连接到一列中
我知道关于同一个问题有多个问题,但我找不到一个可以解决我问题的问题。我也知道这一点,这正是我在下面代码中使用的。我只是有点小问题 表a:Sql 使用Oracle中带有3个相关表的函数将多行连接到一列中,sql,oracle,function,string,plsql,Sql,Oracle,Function,String,Plsql,我知道关于同一个问题有多个问题,但我找不到一个可以解决我问题的问题。我也知道这一点,这正是我在下面代码中使用的。我只是有点小问题 表a: a_id a_name 1 aaa 2 bbb 3 ccc b_id b_name 1 ddd 2 eee 3 fff 表b: a_id a_name 1 aaa 2 bbb 3 ccc b_id b_name 1
a_id a_name
1 aaa
2 bbb
3 ccc
b_id b_name
1 ddd
2 eee
3 fff
表b:
a_id a_name
1 aaa
2 bbb
3 ccc
b_id b_name
1 ddd
2 eee
3 fff
表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
也许我可以使用一些Oracle函数来简化这个过程,比如WM_CONCAT(还没有尝试过),但我需要使用一个函数,这是我在阅读上面链接的文章后的尝试:
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_id, f_test(a_id)
FROM table_c
GROUP BY a_id;
正如上面代码所预期的(不是我想要的,这是我得到的):
我已经尝试了很多关于选择和函数代码的方法,但我似乎无法做到我需要的…您需要将函数更改为类似于:
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
更改SQL查询以获取bnames列表,而不是b_id 从 到
您不应该从表b获取ID,而应该获取名称。首先,正如@OMGPonies所指出的,您需要重写函数,以便它从表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>
同样,您需要在查询中连接到表_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>
哦,那真是个惊喜。关键是,F_测试不是一个聚合函数,因此GROUP BY在这里不起作用,除非我们也包含该函数:
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>
顺便说一句,如果没有GROUPBY子句,我们将得到六行(表C中每行一行)。这是我们不想要的
解决方案的问题在于性能:对于表_C中的每一行,函数执行一次。如果表_B中的任何一个表都很大,那么表_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>
您不需要GROUP BY来使用该函数,也不需要函数外部的JOIN。@OMGPonies-对于您的解决方案来说,这是正确的,因为您已经实现了该函数和查询来驱动表A。OP发布了一些不同的内容,我实现了它。如果表A中有不在表C中的记录,您的解决方案将返回与我不同的结果集(除非您修改查询以连接到表C,我认为这是不公平的-在同一个表上选择两个)。现在,也许表A中的每一行都会有表C中的行,但OP没有向我们提供该业务规则。对不起,很难记住每一个小细节。。。是的,在表C中总会有来自表A的条目。对不起。
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>