Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 使用Oracle中带有3个相关表的函数将多行连接到一列中_Sql_Oracle_Function_String_Plsql - Fatal编程技术网

Sql 使用Oracle中带有3个相关表的函数将多行连接到一列中

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:

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>