任何人都可以帮助我查询以获取oracle中的一对多关系
表结构是:
Table: STUD_NAME Table:CLASS
STUD_No STUD_Name Class_ID STUD_No CLASS_NAME
------------------- -------------------------------------------
1 Sam 1 1 PHYSICS
2 Michael 2 1 MATHEMATICS
3 Patrick 3 2 PHYSICS
5 Leena 4 2 CHEMISTRY
我尝试使用连接概念,因此它返回了STUD_NAME表中的重复行,如
1 Sam PHYSICS
1 Sam CHEMISTRY
我需要像
这样的输出1 Sam PHYSICS,MATHEMATICS
2 Michael PHYSICS,CHEMISTRY
答案 0 :(得分:1)
CREATE OR REPLACE TYPE t_string_agg AS OBJECT
(
g_string VARCHAR2(32767),
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT t_string_agg)
RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT t_string_agg,
value IN VARCHAR2 )
RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateTerminate(self IN t_string_agg,
returnValue OUT VARCHAR2,
flags IN NUMBER)
RETURN NUMBER,
MEMBER FUNCTION ODCIAggregateMerge(self IN OUT t_string_agg,
ctx2 IN t_string_agg)
RETURN NUMBER
);
/
SHOW ERRORS
CREATE OR REPLACE TYPE BODY t_string_agg IS
STATIC FUNCTION ODCIAggregateInitialize(sctx IN OUT t_string_agg)
RETURN NUMBER IS
BEGIN
sctx := t_string_agg(NULL);
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateIterate(self IN OUT t_string_agg,
value IN VARCHAR2 )
RETURN NUMBER IS
BEGIN
SELF.g_string := self.g_string || ',' || value;
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateTerminate(self IN t_string_agg,
returnValue OUT VARCHAR2,
flags IN NUMBER)
RETURN NUMBER IS
BEGIN
returnValue := RTRIM(LTRIM(SELF.g_string, ','), ',');
RETURN ODCIConst.Success;
END;
MEMBER FUNCTION ODCIAggregateMerge(self IN OUT t_string_agg,
ctx2 IN t_string_agg)
RETURN NUMBER IS
BEGIN
SELF.g_string := SELF.g_string || ',' || ctx2.g_string;
RETURN ODCIConst.Success;
END;
END;
/
SHOW ERRORS
CREATE OR REPLACE FUNCTION string_agg (p_input VARCHAR2)
RETURN VARCHAR2
PARALLEL_ENABLE AGGREGATE USING t_string_agg;
/
SHOW ERRORS
然后执行
select stud_name, string_agg(class_name)
from stud_name s, class c
where s.stud_no = c.stud_no
group by stud_name
告诉asktom.oracle.com
答案 1 :(得分:1)
对于9i使用:
select S.STUD_NO, STUD_NAME, WM_CONCAT(CLASS_NAME)
from STUD_NAME S, CLASS C
where S.STUD_NO = C.STUD_NO
group by S.STUD_NO, STUD_NAME
对于11g以上,您可以使用listagg
代替wm_concat
。有关字符串聚合技术的详细列表,请参阅here。
答案 2 :(得分:1)
您应该可以使用SYS_CONNECT_BY_PATH函数执行此操作。对于您的示例,以下内容应该起作用:
select
stud_no,
stud_name,
substr(SYS_CONNECT_BY_PATH(class_name, ', '),2) classes
from
(
select
cn.stud_no,
sn.stud_name,
cn.class_name,
count(*) OVER ( partition by cn.stud_no ) cnt,
ROW_NUMBER () OVER ( partition by cn.stud_no order by cn.class_name) seq
from
class_name cn
,stud_name sn
where
sn.stud_no = cn.stud_no
group by cn.stud_no, sn.stud_name, cn.class_name)
where
seq=cnt
start with
seq=1
connect by prior
seq+1=seq
and prior
stud_no=stud_no;
要打破这个......
内部查询
select
sn.stud_no,
sn.stud_name,
cn.class_name,
count(*) OVER ( partition by cn.stud_no ) cnt,
ROW_NUMBER () OVER ( partition by cn.stud_no order by cn.class_name) seq
from
class_name cn
,stud_name sn
where
sn.stud_no = cn.stud_no
group by cn.stud_no, sn.stud_name, cn.class_name
将给出如下结果集:
STUD_NO STUD_NAME CLASS_NAME CNT SEQ
001 SAM CHEMISTRY 2 1
001 SAM PHYSICS 2 2
002 MICHAEL ART 3 1
002 MICHAEL HISTORY 3 2
002 MICHAEL PHYSICS 3 3
请注意,结果集是按顺序排列的,以便根据stud_no将每个学生的班级记录分组在一起。 CNT表示记录所属的组(分区)中的记录总数(通过包括具有相同stud_no的所有记录的总数),SEQ表示该组内的唯一序列/等级(在这种情况下,基于按类名字母顺序排列。)
然后,查询的其余部分通过使用CNT和SEQ值遍历结果集来为每个学生构建逗号分隔的类名列表,如下所示:
substr(SYS_CONNECT_BY_PATH(class_name, ', '),2) classes
-- builds a list of class names separated by a comma
-- (the substr function is just there to remove the first delimiter)
where seq=cnt -- this condition indicates the last record in each group/list
start with seq=1
-- the starting point for each group (i.e. start a new list every time a seq
-- value of 1 is encountered while traversing the result set)
connect by prior seq+1=seq and prior stud_no=stud_no
-- defines the connection between one list element and the next; the next
-- element in a list will have the same stud_no as the prior element AND a
-- seq equal to the prior element's seq +1
结果:
STUD_NO STUD_NAME CLASSES
001 SAM CHEMISTRY, PHYSICS
002 MICHAEL ART, HISTORY, PHYSICS
此处描述了此方法和其他一些可能的选项:http://www.dba-oracle.com/t_converting_rows_columns.htm
希望有所帮助!
答案 3 :(得分:0)
问题的格式很糟糕,但让我试着理解。
表:STUD_NAME Cols:STUD_No,STUD_Name
表:CLASS Cols:Class_ID,STUD_No,CLASS_NAME
查询应该返回每个学生和他们正在上课的课程。
这是我在SQLite中做的一个例子......告诉我出了什么问题......
sqlite> create table stud_name (stud_no integer, stud_name text);
sqlite> create table class (class_id integer, stud_no integer, class_name text);
sqlite> insert into stud_name values (1, 'Sam');
sqlite> insert into stud_name values (2, 'Mike');
sqlite> insert into stud_name values (3, 'Pat');
sqlite> insert into stud_name values (4, 'Leena');
sqlite> insert into class values (1,1,'Physics');
sqlite> insert into class values (2,1,'Math');
sqlite> insert into class values (3,2,'Physics');
sqlite> select stud_name, class_name from stud_name s, class c
...> where s.stud_no = c.stud_no;
Sam|Math
Sam|Physics
Mike|Physics
答案 4 :(得分:0)
好的,在SQLite中我能够通过......完成。
sqlite> select stud_name, group_concat(class_name)
...> from stud_name s, class c
...> where s.stud_no = c.stud_no
...> group by stud_name
...> ;
Mike|Physics
Sam|Math,Physics
在Oracle 9i中,我相信你可以用wm_concat替换上面的group_concat。
让我知道!