您应该能够使用 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
希望有帮助!