我确信这有一个简单的答案,但我只花了最后3个小时搜索谷歌无济于事。所以,我们有两个三个表 - 课程,学生和课程_学生
courses_students包含课程和学生的主键,可以打破m:m关系。
我的家庭作业要我写一个查询来显示特定课程的所有细节......包括该课程中所有学生的列表。我尝试使用各种类型的连接,但最终获得了多行的课程信息。
即。它应该一次显示课程的详细信息,并包括所有学生,例如
courseid coursename student
------------ ---------------- ---------------
1 math john jackson
jack johnson
john smith
2 english jane doe
michael thomas
等等......请帮忙!
谢谢!
P.S。我正在使用oracle
答案 0 :(得分:1)
SQL并不真正处理分层数据,而是处理集合。这可以在2个查询中更好地处理 - 一个返回课程信息,一个返回课程中的学生。
答案 1 :(得分:1)
查找用户定义的聚合函数。 如果你真的需要在一列中列出它们,你可以设置一个聚合函数,它会为你做到这一点。
Declare
sql_txt Varchar2(4000);
Rec_cnt Number;
Begin
Select Count(*)
Into Rec_Cnt
From User_Types
Where Type_Name = 'VCARRAY'
And Typecode = 'COLLECTION';
If Rec_Cnt = 0 Then
EXECUTE IMMEDIATE 'CREATE OR REPLACE TYPE vcArray as table of varchar2(32000)';
END IF;
END;
/
CREATE OR REPLACE TYPE comma_list_agr_type as object
(
data vcArray,
static function
ODCIAggregateInitialize(sctx IN OUT comma_list_agr_type )
return number,
member function
ODCIAggregateIterate(self IN OUT comma_list_agr_type ,
value IN varchar2 )
return number,
member function
ODCIAggregateTerminate(self IN comma_list_agr_type,
returnValue OUT varchar2,
flags IN number)
return number,
member function
ODCIAggregateMerge(self IN OUT comma_list_agr_type,
ctx2 IN comma_list_agr_type)
return number
);
/
CREATE OR REPLACE TYPE BODY comma_list_agr_type
is
static function ODCIAggregateInitialize(sctx IN OUT comma_list_agr_type)
return number
is
begin
sctx := comma_list_agr_type( vcArray() );
return ODCIConst.Success;
end;
member function ODCIAggregateIterate(self IN OUT comma_list_agr_type,
value IN varchar2 )
return number
is
begin
data.extend;
data(data.count) := value;
return ODCIConst.Success;
end;
member function ODCIAggregateTerminate(self IN comma_list_agr_type,
returnValue OUT varchar2,
flags IN number)
return number
is
l_data varchar2(32000);
begin
for x in ( select column_value from TABLE(data) order by 1 )
loop
l_data := l_data || ',' || x.column_value;
end loop;
returnValue := ltrim(l_data,',');
return ODCIConst.Success;
end;
member function ODCIAggregateMerge(self IN OUT comma_list_agr_type,
ctx2 IN comma_list_agr_type)
return number
is
begin -- not really tested ;)
for i in 1 .. ctx2.data.count
loop
data.extend;
data(data.count) := ctx2.data(i);
end loop;
return ODCIConst.Success;
end;
end;
/
CREATE OR REPLACE FUNCTION comma_list(input varchar2 )
RETURN varchar2
PARALLEL_ENABLE AGGREGATE USING comma_list_agr_type;
/
GRANT EXECUTE ON COMMA_LIST to someuser
/
答案 2 :(得分:1)
有几种不同的方法可以解决这个问题。最简单的是表现形式:在前端显示器中解决它。在SQL * Plus中,它将是BREAK关键字:
SQL> BREAK ON courseid ON coursename
SQL>
SQL> select c.courseid
2 , c.coursename
3 , s.studentname
4 from courses c
5 join course_students cs
6 on ( cs.courseid = c.courseid )
7 join students s
8 on ( s.studentid = cs.studentid )
9 /
COURSEID COURSENAME STUDENTNAME
---------- ---------- --------------------
1 math john smith
jack jackson
john jackson
2 english michael thomas
jane doe
SQL>
另一种方法是使用嵌入式光标:
SQL> select c.courseid
2 , c.coursename
3 , cursor (select s.studentname
4 from course_students cs
5 join students s
6 on ( s.studentid = cs.studentid )
7 where cs.courseid = c.courseid
8 )
9 from courses c
10 /
COURSEID COURSENAME CURSOR(SELECTS.STUDE
---------- ---------- --------------------
1 math CURSOR STATEMENT : 3
CURSOR STATEMENT : 3
STUDENTNAME
--------------------
john smith
john jackson
jack jackson
2 english CURSOR STATEMENT : 3
CURSOR STATEMENT : 3
STUDENTNAME
--------------------
jane doe
michael thomas
SQL>
我们可以辩论这是否真的算作“单行”:)
最后我们有字符串聚合技术。切片这种特殊的卷心菜有很多不同的方法,因为 - 令人难以置信的是 - 直到最新版本,Oracle才提供标准的内置功能。因为我不在11gR2上,所以我将使用WM_CONCAT()而不是LISTAGG():
SQL> select c.courseid
2 , c.coursename
3 , wm_concat(s.studentname) as studentnames
4 from courses c
5 join course_students cs
6 on ( cs.courseid = c.courseid )
7 join students s
8 on ( s.studentid = cs.studentid )
9 group by c.courseid
10 , c.coursename
11 /
COURSEID COURSENAME STUDENTNAMES
---------- ---------- ---------------------------------------------
1 math john smith,john jackson,jack jackson
2 english jane doe,michael thomas
SQL>
Tim Hall的Oracle-Base网站汇总了所有字符串聚合选项。 Find out more
答案 3 :(得分:0)
如果您只是在查询中需要结果,为什么不呢?
with courses as
(select 'biology' coursename, 1 courseid from dual
union
select 'chemistry' coursename, 2 courseid from dual)
,
students as
(select 'Sally' studentName, 1 studentId from dual
union
select 'Jonny' studentName, 2 studentId from dual
union
select 'Tom' studentName, 3 studentId from dual
union
select 'Jane' studentName, 4 studentId from dual
) ,
courses_students as
(select 1 studentId, 1 courseId from dual
union
select 1 studentId, 2 courseId from dual
union
select 2 studentId, 1 courseId from dual
union
select 3 studentId, 2 courseId from dual
)
select c.courseName ,
cursor(select s.StudentName
from students s
inner join
courses_students cs
on s.studentId = cs.studentId
where cs.courseId = c.courseId) students
from courses c ;
授予没有类型,但这将工作。
COURSENAME STUDENTS
---------- --------
biology STUDENTNAME
-----------
Sally
Jonny
chemistry STUDENTNAME
-----------
Sally
Tom
所有在一个查询中,字面上没什么太花哨的(只使用CURSOR语句)
如果您使用11gr2 ListAgg效果很好
答案 4 :(得分:0)
您所在的Oracle版本?如果您使用的是Oracle DB 11g R2,请查看 listagg
。
SQL> select deptno,
2 listagg( ename, '; ' )
3 within group
4 (order by ename) enames
5 from hr.employees
6 group by deptno
7 order by deptno
8 /
DEPTNO ENAMES
--------- --------------------
10 CLARK; KING; MILLER
20 ADAMS; FORD; JONES;
SCOTT; SMITH
30 ALLEN; BLAKE;
JAMES; MARTIN;
TURNER; WARD
您的案例需要在课程表中进行。在以前的版本中,您可以使用CONNECT BY
子句。有关listagg
的更多详情。
答案 5 :(得分:0)
sql suck(真的...... ??? !!),
首先要澄清的是问题的意图是以该格式呈现数据(或)查询本身是否应以此格式显示数据。
a)如果只是演示文稿,请看一下SQLPLUS“break on”。这允许你做的是在特定列上中断,如果值没有改变则不重复相同的值。
b)1)如果是以这种格式输出数据的查询,那么请查看上面“拼写”所建议的方法。如果您想探索更多选项,2)查看超前和滞后函数。您可以使用这些函数查看上一行中列的值。如果它们相同,则显示null,否则显示实际值。
Imp: 对于选项a)和b(2),您应该使用order by子句对结果进行排序。 (为什么..?)
另外,请检查此链接:How do I remove repeated column values from report